const express = require('express');
const cors = require('cors');
const axios = require('axios');
const fs = require('fs');
const path = require('path');
require('dotenv').config();

// ??????????????????
const pool = require('./config/database');
// ????????????
const paymentUtils = require('./utils/payment');

// ??????????????const multer = require('multer');

// ????????????
const uploadDir = path.join(__dirname, 'uploads');
if (!fs.existsSync(uploadDir)) {
    fs.mkdirSync(uploadDir, { recursive: true });
}

// ???multer
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, uploadDir);
    },
    filename: function (req, file, cb) {
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
        const fileExt = path.extname(file.originalname);
        cb(null, 'avatar-' + uniqueSuffix + fileExt);
    }
});

const upload = multer({ 
    storage: storage,
    limits: { fileSize: 5 * 1024 * 1024 }, // ???5MB
    fileFilter: function (req, file, cb) {
        const filetypes = /jpeg|jpg|png|gif/;
        const mimetype = filetypes.test(file.mimetype);
        const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
        
        if (mimetype && extname) {
            return cb(null, true);
        }
        cb(new Error('???????????jpeg, jpg, png, gif)'));
    }
});

const app = express();
const port = process.env.PORT || 5000;

// ?????app.use(cors());
app.use(express.json());
app.use(express.text({ type: 'application/xml' })); // ????????????
app.use(express.urlencoded({ extended: true })); // ??????????????
// ???????????app.use((req, res, next) => {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
    console.log('?????', req.body);
    next();
});

// ????????????????????????????????????????????operation/target_type/target_id/ip_address/user_agent??app.use(async (req, res, next) => {
    const modMethods = ['POST', 'PUT', 'PATCH', 'DELETE'];
    if (!modMethods.includes(req.method)) return next();

    // ???????????????????????????????????    if (req.path === '/api/auth/wechat/callback') return next();

    try {
        // ?????? NULL ??? admin_id????????????
        // ???????????NULL??????????????????????D
        let adminId = 0;
        try {
            const [admins] = await pool.execute(
                'SELECT id FROM users WHERE role = "admin" OR role = 100 OR permission_level >= 50 LIMIT 1'
            );
            if (admins.length > 0) {
                adminId = admins[0].id;
            }
        } catch (e) {
            // ????????????????????????????????            adminId = null;
        }

        // ????????????????????????????????        if (adminId && adminId > 0) {
            try {
                await pool.execute(
                    `INSERT INTO admin_operation_logs (admin_id, operation_type, target_id, target_type, operation_details, ip_address, user_agent)
             VALUES (?, ?, NULL, 'api', ?, ?, ?)`,
                    [adminId, `${req.method}:${req.path}`, JSON.stringify(req.body || {}), req.ip, req.headers['user-agent']]
                );
            } catch (e) {
                console.warn('????????????(?????:', e.message);
            }
        }
    } catch (e) {
        console.warn('????????????(?????:', e.message);
    }
    next();
});

// ========== ?????? ==========

// ?????????????????
app.get('/api/debug/users', async (req, res) => {
    console.log('?? ???????????);
    try {
        const [users] = await pool.execute(
            'SELECT id, phone, role, login_method, is_phone_verified, created_at FROM users ORDER BY created_at DESC'
        );

        console.log('?? ??????????????', users.length);

        res.json({
            success: true,
            data: {
                total: users.length,
                users: users
            }
        });
    } catch (error) {
        console.error('??????????????:', error);
        res.json({
            success: false,
            message: '????????????: ' + error.message
        });
    }
});

// ========== ????????? ==========

// ????????const adminRoutes = require('./routes/adminRoutes');
const authRoutes = require('./routes/authRoutes');
const orderRoutes = require('./routes/orderRoutes');
const courierRoutes = require('./routes/courierRoutes');
const statisticsRoutes = require('./routes/statisticsRoutes');
const { errorHandler } = require('./utils/errorHandler');

app.use('/api/admin', adminRoutes);
app.use('/api/auth', authRoutes);
app.use('/api/orders', orderRoutes);
app.use('/api/couriers', courierRoutes);
app.use('/api/statistics', statisticsRoutes);


// ??????????????????????????
app.use(errorHandler);

// ??????API
app.post('/api/users/avatar', upload.single('avatar'), async (req, res) => {
    try {
        // ????????????
        const userId = req.user?.id || req.body.userId;
        if (!userId) {
            return res.status(401).json({ success: false, message: '???????? });
        }

        // ???????????????
        if (!req.file) {
            return res.status(400).json({ success: false, message: '??????????????' });
        }

        // ?????????
        const avatarPath = `/uploads/${req.file.filename}`;

        // ?????????????????        const [result] = await pool.query(
            'UPDATE users SET avatar_url = ? WHERE id = ?',
            [avatarPath, userId]
        );

        if (result.affectedRows === 0) {
            // ????????????????????????
            fs.unlinkSync(path.join(uploadDir, req.file.filename));
            return res.status(404).json({ success: false, message: '???????? });
        }

        // ?????????????????RL
        res.status(200).json({
            success: true,
            message: '?????????',
            avatarUrl: avatarPath
        });
    } catch (error) {
        // ?????????????????????
        if (req.file) {
            try {
                fs.unlinkSync(path.join(uploadDir, req.file.filename));
            } catch (unlinkError) {
                console.error('????????????:', unlinkError);
            }
        }
        console.error('?????????:', error);
        res.status(500).json({ success: false, message: '???????????, error: error.message });
    }
});
app.post('/api/auth/direct-test', async (req, res) => {
    console.log('=== ?? ??????????????===');

    try {
        const testPhone = "13058325914";

        // 1. ??????????        console.log('1. ??????????..');
        const [current] = await pool.execute(
            'SELECT id, phone, sms_code FROM users WHERE phone = ?',
            [testPhone]
        );
        console.log('???????', current[0]);

        // 2. ?????????
        const testCode = Math.floor(100000 + Math.random() * 900000).toString();
        console.log('2. ????????', testCode);

        // 3. ????????        console.log('3. ??????...');
        const [updateResult] = await pool.execute(
            'UPDATE users SET sms_code = ? WHERE phone = ?',
            [testCode, testPhone]
        );
        console.log('??????:', updateResult);

        // 4. ??????
        console.log('4. ??????...');
        const [verify] = await pool.execute(
            'SELECT id, phone, sms_code FROM users WHERE phone = ?',
            [testPhone]
        );
        console.log('??????:', verify[0]);

        res.json({
            success: true,
            message: '?????????',
            data: {
                before: current[0],
                after: verify[0],
                updateResult: updateResult,
                generatedCode: testCode
            }
        });

    } catch (error) {
        console.error('??????:', error);
        res.status(500).json({
            success: false,
            message: '??????: ' + error.message
        });
    }
});

// ???????????
app.post('/api/auth/send-email-verification', async (req, res) => {
    const { userId, email } = req.body;
    console.log('?? ????????????????D:', userId, '???:', email);

    if (!userId || !email) {
        return res.status(400).json({
            success: false,
            message: '?????????????serId??mail'
        });
    }

    // ?????????
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
        return res.status(400).json({
            success: false,
            message: '???????????
        });
    }

    try {
        const verificationCode = Math.floor(100000 + Math.random() * 900000).toString();

        // ???????????????????????mail_verification_code??????????????        // ????????????????sers???????????        const [cols] = await pool.execute('SHOW COLUMNS FROM users');
        const hasEmailCode = cols.some(col => col.Field === 'email_verification_code');
        const hasEmailExpires = cols.some(col => col.Field === 'email_code_expires_at');

        if (hasEmailCode) {
            await pool.execute(
                'UPDATE users SET email_verification_code = ?, email_code_expires_at = DATE_ADD(NOW(), INTERVAL 10 MINUTE) WHERE id = ?',
                [verificationCode, userId]
            );
        }

        // ???????????????????????
        let emailSent = false;
        if (process.env.EMAIL_ENABLED === 'true') {
            try {
                const emailUtils = require('./utils/email');
                if (emailUtils && emailUtils.sendEmailVerificationCode) {
                    const result = await emailUtils.sendEmailVerificationCode(email, verificationCode);
                    emailSent = result && result.success;
                    if (!emailSent) {
                        console.warn('??? ????????????????????????????);
                    }
                }
            } catch (emailError) {
                console.warn('??? ???????????????????', emailError.message);
                // ??????????????????????????????
            }
        } else {
            console.log('?? [??????? ???????????????????????????');
        }

        // ???????????????????????????????????        const response = {
            success: true,
            message: emailSent ? '?????????????????' : '?????????',
            data: {
                expiresIn: 600 // 10???
            }
        };

        // ???????????????????????????????????????????
        if (process.env.NODE_ENV !== 'production' || !emailSent) {
            console.log('?? ?????????????????:', verificationCode);
            response.data.debugCode = verificationCode;
            response.data.debug = `???????????????${emailSent ? '' : '???????????????????????}`;
        }

        res.json(response);

    } catch (error) {
        console.error('????????????????:', error);
        res.status(500).json({
            success: false,
            message: '???????????: ' + error.message
        });
    }
});

// ??????
app.post('/api/auth/verify-email', async (req, res) => {
    const { userId, email, verificationCode } = req.body;
    console.log('?????????????D:', userId);

    if (!userId || !email || !verificationCode) {
        return res.status(400).json({
            success: false,
            message: '?????????????serId??mail??erificationCode'
        });
    }

    try {
        // ?????????
        const [users] = await pool.execute(
            'SELECT email_verification_code, email_code_expires_at FROM users WHERE id = ?',
            [userId]
        );

        if (users.length === 0) {
            return res.status(404).json({
                success: false,
                message: '????????
            });
        }

        const user = users[0];

        // ????????
        const storedCode = String(user.email_verification_code || '').trim();
        const inputCode = String(verificationCode).trim();

        if (storedCode !== inputCode) {
            return res.status(400).json({
                success: false,
                message: '????????
            });
        }

        // ??????????????
        if (!user.email_code_expires_at || new Date() > new Date(user.email_code_expires_at)) {
            return res.status(400).json({
                success: false,
                message: '??????????????????'
            });
        }

        // ??????????????????????        const [cols] = await pool.execute('SHOW COLUMNS FROM users');
        const hasEmailVerified = cols.some(col => col.Field === 'email_verified');

        if (hasEmailVerified) {
            await pool.execute(
                'UPDATE users SET email = ?, email_verified = 1, email_verification_code = NULL, email_code_expires_at = NULL WHERE id = ?',
                [email, userId]
            );
        } else {
            await pool.execute(
                'UPDATE users SET email = ?, email_verification_code = NULL, email_code_expires_at = NULL WHERE id = ?',
                [email, userId]
            );
        }

        console.log('????????????????D:', userId);

        res.json({
            success: true,
            message: '?????????'
        });

    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({
            success: false,
            message: '??????: ' + error.message
        });
    }
});

// ??? ??????send-sms ?????? authRoutes.js ????????????
// ??????????backend/routes/authRoutes.js??????????????
// ?????????????app.post('/api/auth/check-nickname', async (req, res) => {
    const { nickname } = req.body;

    if (!nickname || typeof nickname !== 'string') {
        return res.json({ success: false, message: '?????????' });
    }

    const trimmedNickname = nickname.trim();

    if (trimmedNickname.length < 2) {
        return res.json({ success: false, message: '???????????????, data: { available: false } });
    }

    if (trimmedNickname.length > 20) {
        return res.json({ success: false, message: '?????????20?????, data: { available: false } });
    }

    try {
        const [users] = await pool.execute(
            'SELECT id FROM users WHERE nickname = ?',
            [trimmedNickname]
        );

        if (users.length > 0) {
            return res.json({
                success: true,
                message: '???????????,
                data: { available: false }
            });
        }

        res.json({
            success: true,
            message: '??????',
            data: { available: true }
        });

    } catch (error) {
        console.error('????????????', error);
        res.status(500).json({ success: false, message: '??????? });
    }
});

// ???????????- ?????app.post('/api/auth/register-with-sms', async (req, res) => {
    const { phone, smsCode, password, nickname } = req.body;
    console.log('?? ????????????:', phone, '???:', nickname);

    if (!phone || !smsCode || !password) {
        return res.json({ success: false, message: '?????????' });
    }

    // ??????
    if (!nickname || typeof nickname !== 'string') {
        return res.json({ success: false, message: '?????????' });
    }

    const trimmedNickname = nickname.trim();

    if (trimmedNickname.length < 2 || trimmedNickname.length > 20) {
        return res.json({ success: false, message: '???????????-20???????? });
    }

    try {
        // 1. ????????????????        const [nicknameUsers] = await pool.execute(
            'SELECT id FROM users WHERE nickname = ?',
            [trimmedNickname]
        );

        if (nicknameUsers.length > 0) {
            console.log('???????????:', trimmedNickname);
            return res.json({ success: false, message: '????????????????? });
        }

        // 2. ????????????
        const [users] = await pool.execute(
            'SELECT id, sms_code, sms_expires_at, password_hash FROM users WHERE phone = ?',
            [phone]
        );

        // ?????????????????????????????????????        if (users.length === 0) {
            console.log('????????????????????????);
            return res.json({
                success: false,
                message: '???????????
            });
        }

        const user = users[0];

        // 3. ??????????????????????????
        if (user.password_hash) {
            console.log('?????????????);
            return res.json({
                success: false,
                message: '????????????????????,
                code: 'USER_ALREADY_REGISTERED'
            });
        }

        // 4. ??????????????
        if (!user.sms_code) {
            console.log('???????????');
            return res.json({ success: false, message: '??????????? });
        }

        // 5. ??????????????
        if (!user.sms_expires_at || new Date() > new Date(user.sms_expires_at)) {
            console.log('???????????');
            return res.json({ success: false, message: '??????????????????' });
        }

        // 6. ????????        const inputCode = String(smsCode).trim();
        const storedCode = String(user.sms_code).trim();

        console.log(`?? ???????????- ???: "${inputCode}", ???: "${storedCode}"`);

        if (inputCode !== storedCode) {
            console.log(`??????????????`);
            return res.json({ success: false, message: '???????? });
        }

        console.log(`????????????????????????D: ${user.id}`);

        // 7. ???????????????????????????
        const bcrypt = require('bcryptjs');
        const hashedPassword = await bcrypt.hash(password, 10);

        const [result] = await pool.execute(
            'UPDATE users SET password_hash = ?, nickname = ?, sms_code = NULL, sms_expires_at = NULL, is_phone_verified = 1, login_method = ? WHERE id = ?',
            [hashedPassword, trimmedNickname, 'password', user.id]
        );

        if (result.affectedRows === 0) {
            console.log('??????????????');
            return res.json({ success: false, message: '????????????' });
        }

        console.log(`?? ???????????D: ${user.id}`);

        res.json({
            success: true,
            message: '??????',
            data: {
                userId: user.id,
                phone: phone
            }
        });

    } catch (error) {
        console.error('????????:', error);
        res.status(500).json({
            success: false,
            message: '??????: ' + error.message
        });
    }
});

// ??????????????app.post('/api/auth/login-with-sms', async (req, res) => {
    console.log('=== ?? ????????- ????===');
    const { phone, smsCode } = req.body;

    console.log(`?? ???????? ${phone}`);
    console.log(`?? ???????? ${smsCode}`);

    try {
        // ?????????
        const [users] = await pool.execute(
            'SELECT id, sms_code, sms_expires_at, password_hash FROM users WHERE phone = ?',
            [phone]
        );

        console.log('?? ???????????', users[0]);

        if (users.length === 0) {
            console.log('??????????);
            return res.json({ success: false, message: '??????????????????' });
        }

        const user = users[0];

        // ????????
        if (!user.sms_code) {
            console.log('???????????');
            return res.json({ success: false, message: '??????????? });
        }

        // ??????????????
        const inputCode = String(smsCode).trim();
        const storedCode = String(user.sms_code).trim();

        console.log(`?? ????????- ???: "${inputCode}", ???: "${storedCode}"`);

        if (inputCode !== storedCode) {
            console.log(`???????????`);
            return res.json({ success: false, message: '???????? });
        }

        // ??????????????
        if (new Date() > new Date(user.sms_expires_at)) {
            console.log('???????????');
            return res.json({ success: false, message: '?????????' });
        }

        // ?????????????        if (!user.password_hash) {
            console.log('??? ???????????);
            return res.json({
                success: false,
                message: '?????????',
                code: 'NEED_REGISTER',
                data: { userId: user.id }
            });
        }

        console.log(`?? ???????????D: ${user.id}`);

        // ????????????
        const [userInfo] = await pool.execute(
            'SELECT role, account_status, nickname, avatar_url FROM users WHERE id = ?',
            [user.id]
        );

        const role = userInfo[0]?.role || 'order_user';

        // ???JWT Token
        const { generateAccessToken, generateRefreshToken } = require('./utils/jwt');
        const accessToken = generateAccessToken({
            userId: user.id,
            role: role
        });

        const refreshToken = generateRefreshToken({
            userId: user.id
        });

        // ???????????P
        const clientIp = req.ip || req.headers['x-forwarded-for'] || '???';
        const [cols] = await pool.execute('SHOW COLUMNS FROM users');
        const hasLastLogin = cols.some(col => col.Field === 'last_login_at');
        const hasLastLoginIp = cols.some(col => col.Field === 'last_login_ip');

        if (hasLastLogin) {
            const updateFields = ['last_login_at = NOW()'];
            const updateParams = [];
            if (hasLastLoginIp) {
                updateFields.push('last_login_ip = ?');
                updateParams.push(clientIp);
            }
            updateParams.push(user.id);
            await pool.execute(
                `UPDATE users SET ${updateFields.join(', ')} WHERE id = ?`,
                updateParams
            );
        }

        // ???????????????login_logs???
        try {
            const [logTable] = await pool.execute("SHOW TABLES LIKE 'login_logs'");
            if (logTable.length > 0) {
                await pool.execute(
                    `INSERT INTO login_logs (user_id, login_at, ip_address, user_agent) 
                     VALUES (?, NOW(), ?, ?)`,
                    [user.id, clientIp, req.headers['user-agent'] || '???']
                );
            }
        } catch (e) {
            console.warn('????????????????????', e.message);
        }

        // ???????????????
        await pool.execute(
            'UPDATE users SET sms_code = NULL, sms_expires_at = NULL WHERE id = ?',
            [user.id]
        );

        // ?????oken????????        return res.json({
            success: true,
            message: '??????',
            data: {
                token: accessToken,
                refreshToken: refreshToken,
                userId: user.id,
                userInfo: {
                    phone: phone,
                    nickname: userInfo[0]?.nickname,
                    avatarUrl: userInfo[0]?.avatar_url,
                    role: role
                }
            }
        });

    } catch (error) {
        console.error('?? ??????:', error);
        res.status(500).json({
            success: false,
            errorCode: 5001,
            errorMessage: '??????: ' + error.message
        });
    }
});


// ?????????
// ??? ??????login-with-password ?????? authRoutes.js ????????????
// ??????????backend/routes/authRoutes.js??????????????
// ========== ????????? ==========

// ========== ??????????????==========

// ?????????
app.post('/api/feedback', async (req, res) => {
    const { userId, userType, content, contact } = req.body;
    console.log('?? ??????????????D:', userId);

    if (!userId || !content) {
        return res.status(400).json({
            success: false,
            message: '?????????????serId??ontent'
        });
    }

    try {
        // ????????feedback??        const [tableCheck] = await pool.execute("SHOW TABLES LIKE 'feedback'");

        if (tableCheck.length === 0) {
            // ???feedback??            await pool.execute(`
                CREATE TABLE IF NOT EXISTS feedback (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    user_id INT,
                    user_type VARCHAR(20) DEFAULT 'order_user',
                    user_name VARCHAR(255),
                    content TEXT NOT NULL,
                    contact VARCHAR(255),
                    is_read TINYINT DEFAULT 0,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    INDEX idx_user_id (user_id),
                    INDEX idx_is_read (is_read),
                    INDEX idx_created_at (created_at)
                )
            `);
            console.log('?????feedback?????);
        }

        // ?????????
        const [users] = await pool.execute(
            'SELECT nickname, phone FROM users WHERE id = ?',
            [userId]
        );

        const userName = users[0]?.nickname || users[0]?.phone || '??????';

        // ??????
        const [result] = await pool.execute(
            `INSERT INTO feedback (user_id, user_type, user_name, content, contact, is_read)
             VALUES (?, ?, ?, ?, ?, 0)`,
            [userId, userType || 'order_user', userName, content, contact || null]
        );

        console.log('?????????????D:', result.insertId);

        res.json({
            success: true,
            message: '?????????',
            data: {
                feedbackId: result.insertId
            }
        });

    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({
            success: false,
            message: '?????????: ' + error.message
        });
    }
});

// ??????????????app.get('/api/admin/feedback', async (req, res) => {
    console.log('?? ??????????????);

    try {
        const [tableCheck] = await pool.execute("SHOW TABLES LIKE 'feedback'");

        if (tableCheck.length === 0) {
            return res.json({
                success: true,
                data: []
            });
        }

        const [feedbacks] = await pool.execute(
            'SELECT * FROM feedback ORDER BY created_at DESC LIMIT 100'
        );

        res.json({
            success: true,
            data: feedbacks
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({
            success: false,
            message: '????????????: ' + error.message
        });
    }
});

// ???????????????
app.put('/api/admin/feedback/:id/read', async (req, res) => {
    const { id } = req.params;
    console.log('??????????????ID:', id);

    try {
        const [tableCheck] = await pool.execute("SHOW TABLES LIKE 'feedback'");

        if (tableCheck.length === 0) {
            return res.status(404).json({
                success: false,
                message: '?????????'
            });
        }

        await pool.execute(
            'UPDATE feedback SET is_read = 1 WHERE id = ?',
            [id]
        );

        res.json({
            success: true,
            message: '??????'
        });

    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({
            success: false,
            message: '??????: ' + error.message
        });
    }
});

// ???????????app.delete('/api/admin/feedback/:id', async (req, res) => {
    const { id } = req.params;
    console.log('????????????D:', id);

    try {
        const [tableCheck] = await pool.execute("SHOW TABLES LIKE 'feedback'");

        if (tableCheck.length === 0) {
            return res.status(404).json({
                success: false,
                message: '?????????'
            });
        }

        await pool.execute('DELETE FROM feedback WHERE id = ?', [id]);

        res.json({
            success: true,
            message: '??????'
        });

    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({
            success: false,
            message: '??????: ' + error.message
        });
    }
});

// ???????????app.post('/api/admin/feedback/reply', async (req, res) => {
    const { feedbackId, content } = req.body;
    console.log('?? ???????????????ID:', feedbackId);

    if (!feedbackId || !content) {
        return res.status(400).json({
            success: false,
            message: '?????????????eedbackId??ontent'
        });
    }

    try {
        const [tableCheck] = await pool.execute("SHOW TABLES LIKE 'feedback_replies'");

        if (tableCheck.length === 0) {
            // ???feedback_replies??            await pool.execute(`
                CREATE TABLE IF NOT EXISTS feedback_replies (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    feedback_id INT NOT NULL,
                    admin_id INT,
                    content TEXT NOT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    INDEX idx_feedback_id (feedback_id)
                )
            `);
        }

        // ??????
        await pool.execute(
            `INSERT INTO feedback_replies (feedback_id, admin_id, content)
             VALUES (?, NULL, ?)`,
            [feedbackId, content]
        );

        // ???????????        try {
            await pool.execute(
                'UPDATE feedback SET is_read = 1 WHERE id = ?',
                [feedbackId]
            );
        } catch (e) {
            console.warn('?????????????????', e.message);
        }

        console.log('????????');

        res.json({
            success: true,
            message: '??????'
        });

    } catch (error) {
        console.error('????????:', error);
        res.status(500).json({
            success: false,
            message: '??????: ' + error.message
        });
    }
});

// ?????????
app.get('/api/users/:userId/login-history', async (req, res) => {
    const { userId } = req.params;
    const { limit = 10 } = req.query;
    console.log('?? ??????????????D:', userId);

    try {
        // ????????last_login_at???
        const [cols] = await pool.execute('SHOW COLUMNS FROM users');
        const hasLastLogin = cols.some(col => col.Field === 'last_login_at');

        if (!hasLastLogin) {
            return res.json({
                success: true,
                data: []
            });
        }

        // ??????????????        // ????????????????????ast_login_at
        // ??????????????????login_logs?????????????????        const [users] = await pool.execute(
            'SELECT last_login_at, last_login_ip FROM users WHERE id = ?',
            [userId]
        );

        const loginHistory = [];
        if (users.length > 0 && users[0].last_login_at) {
            loginHistory.push({
                device: '??????',
                location: users[0].last_login_ip || '???',
                time: users[0].last_login_at,
                isCurrent: true
            });
        }

        // ?????ogin_logs????????????????????        try {
            const [logTable] = await pool.execute("SHOW TABLES LIKE 'login_logs'");
            if (logTable.length > 0) {
                const [logs] = await pool.execute(
                    `SELECT login_at, ip_address, user_agent 
                     FROM login_logs 
                     WHERE user_id = ? 
                     ORDER BY login_at DESC 
                     LIMIT ?`,
                    [userId, parseInt(limit)]
                );

                // ??????
                logs.forEach(log => {
                    const userAgent = log.user_agent || '';
                    let device = '??????';
                    if (userAgent.includes('Windows')) device = 'Windows';
                    else if (userAgent.includes('iPhone') || userAgent.includes('iOS')) device = 'iPhone';
                    else if (userAgent.includes('Android')) device = 'Android';
                    else if (userAgent.includes('iPad')) device = 'iPad';
                    else if (userAgent.includes('Mac')) device = 'Mac';

                    loginHistory.push({
                        device: device,
                        location: log.ip_address || '???',
                        time: log.login_at,
                        isCurrent: false
                    });
                });
            }
        } catch (e) {
            console.warn('???login_logs?????', e.message);
        }

        res.json({
            success: true,
            data: loginHistory
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({
            success: false,
            message: '????????????: ' + error.message
        });
    }
});

// ?????????
app.put('/api/users/change-password', async (req, res) => {
    const { userId, oldPassword, newPassword } = req.body;
    console.log('?? ??????????????D:', userId);

    if (!userId || !oldPassword || !newPassword) {
        return res.status(400).json({
            success: false,
            message: '?????????????serId??ldPassword??ewPassword'
        });
    }

    if (newPassword.length < 6) {
        return res.status(400).json({
            success: false,
            message: '?????????????
        });
    }

    try {
        const bcrypt = require('bcryptjs');

        // 1. ?????????
        const [users] = await pool.execute(
            'SELECT id, password_hash FROM users WHERE id = ?',
            [userId]
        );

        if (users.length === 0) {
            return res.status(404).json({
                success: false,
                message: '????????
            });
        }

        const user = users[0];

        // 2. ?????????????????????????        if (!user.password_hash) {
            return res.status(400).json({
                success: false,
                message: '??????????????????????????????'
            });
        }

        // 3. ????????        const isOldPasswordValid = await bcrypt.compare(oldPassword, user.password_hash);

        if (!isOldPasswordValid) {
            console.log('?????????????);
            return res.status(400).json({
                success: false,
                message: '????????
            });
        }

        // 4. ????????????????????
        const isSamePassword = await bcrypt.compare(newPassword, user.password_hash);
        if (isSamePassword) {
            return res.status(400).json({
                success: false,
                message: '?????????????????
            });
        }

        // 5. ????????        const hashedNewPassword = await bcrypt.hash(newPassword, 10);

        // 6. ??????
        const [result] = await pool.execute(
            'UPDATE users SET password_hash = ?, password_changed_at = NOW() WHERE id = ?',
            [hashedNewPassword, userId]
        );

        if (result.affectedRows === 0) {
            return res.status(500).json({
                success: false,
                message: '?????????'
            });
        }

        console.log('????????????????D:', userId);

        res.json({
            success: true,
            message: '?????????'
        });

    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({
            success: false,
            message: '?????????: ' + error.message
        });
    }
});

// ???????????????????? /api/users/:userId ??????????????app.get('/api/users/admins', async (req, res) => {
    try {
        const [rows] = await pool.execute(`
            SELECT id, phone, nickname, avatar_url
            FROM users
            WHERE role = 'admin' OR role = 100 OR permission_level >= 50
            LIMIT 10
        `);
        res.json({ success: true, data: rows || [] });
    } catch (e) {
        console.error('????????????????', e);
        res.status(500).json({ success: false, message: '?????????????? ' + e.message });
    }
});

// ?????????
app.get('/api/users/:userId', async (req, res) => {
    const { userId } = req.params;
    console.log('?? ??????????????D:', userId);

    try {
        const [users] = await pool.execute(
            'SELECT id, phone, nickname, avatar, role FROM users WHERE id = ?',
            [userId]
        );

        if (users.length === 0) {
            return res.json({
                success: false,
                message: '????????
            });
        }

        res.json({
            success: true,
            data: users[0]
        });
    } catch (error) {
        console.error('??????????????:', error);
        res.json({
            success: false,
            message: '????????????'
        });
    }
});

// ???????????????????????????? ????????? /api/users/:userId ???
// ??????????????app.get('/api/users/list-admin/stats', async (req, res) => {
    try {
        // ??????????????????????????????order_users???
        const [totalCount] = await pool.execute(
            `SELECT COUNT(DISTINCT u.id) AS total
             FROM users u
             WHERE EXISTS (
                 SELECT 1 FROM orders o 
                 INNER JOIN order_users ou ON ou.id = o.order_user_id 
                 WHERE ou.user_id = u.id
             )`
        );

        // ???????????0??????????????        const [activeCount] = await pool.execute(
            `SELECT COUNT(DISTINCT u.id) AS total
             FROM users u
             WHERE EXISTS (
                 SELECT 1 FROM orders o 
                 INNER JOIN order_users ou ON ou.id = o.order_user_id 
                 WHERE ou.user_id = u.id
             )
             AND (u.last_login_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) 
                  OR u.account_status = 'active' 
                  OR u.is_phone_verified = 1
                  OR EXISTS (
                      SELECT 1 FROM orders o2 
                      INNER JOIN order_users ou2 ON ou2.id = o2.order_user_id 
                      WHERE ou2.user_id = u.id 
                      AND o2.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
                  ))`
        );

        // VIP?????????>=90 ???????????>0 ???????=10??        const [vipCount] = await pool.execute(
            `SELECT COUNT(DISTINCT u.id) AS total
             FROM users u
             WHERE EXISTS (
                 SELECT 1 FROM orders o 
                 INNER JOIN order_users ou ON ou.id = o.order_user_id 
                 WHERE ou.user_id = u.id
             )
             AND (
                 EXISTS (SELECT 1 FROM order_users ou3 WHERE ou3.user_id = u.id AND ou3.credit_score >= 90)
                 OR EXISTS (SELECT 1 FROM order_users ou4 WHERE ou4.user_id = u.id AND ou4.timely_payments > 0)
                 OR (SELECT COUNT(*) FROM orders o2 
                     INNER JOIN order_users ou5 ON ou5.id = o2.order_user_id 
                     WHERE ou5.user_id = u.id) >= 10
             )`
        );

        // ?????????????????????
        const [newCount] = await pool.execute(
            `SELECT COUNT(DISTINCT u.id) AS total
             FROM users u
             WHERE EXISTS (
                 SELECT 1 FROM orders o 
                 INNER JOIN order_users ou ON ou.id = o.order_user_id 
                 WHERE ou.user_id = u.id
             )
             AND MONTH(u.created_at) = MONTH(NOW())
             AND YEAR(u.created_at) = YEAR(NOW())`
        );

        res.json({
            success: true,
            data: {
                total: totalCount[0]?.total || 0,
                active: activeCount[0]?.total || 0,
                vip: vipCount[0]?.total || 0,
                newThisMonth: newCount[0]?.total || 0
            }
        });
    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '?????????' });
    }
});

app.get('/api/users/list-admin', async (req, res) => {
    const { page = 1, pageSize = 20, keyword = '', category = 'all' } = req.query || {};
    const offset = (Number(page) - 1) * Number(pageSize);

    // ??????????????????????????????    // ?????rders??????????????????????????order_users????????    const where = [`EXISTS (
        SELECT 1 FROM orders o 
        INNER JOIN order_users ou2 ON ou2.id = o.order_user_id 
        WHERE ou2.user_id = u.id
    )`];
    const params = [];

    if (keyword) {
        where.push('(u.phone LIKE ? OR u.nickname LIKE ? OR u.email LIKE ?)');
        params.push(`%${keyword}%`, `%${keyword}%`, `%${keyword}%`);
    }

    // ?????ctive/vip/disabled
    if (category === 'active') {
        where.push("(u.account_status = 'active' OR u.is_phone_verified = 1 OR u.last_login_at >= DATE_SUB(NOW(), INTERVAL 30 DAY))");
    } else if (category === 'vip') {
        // VIP????????????????????order_users???
        where.push(`(
            EXISTS (SELECT 1 FROM order_users ou3 WHERE ou3.user_id = u.id AND ou3.credit_score >= 90)
            OR EXISTS (SELECT 1 FROM order_users ou4 WHERE ou4.user_id = u.id AND ou4.timely_payments > 0)
            OR (SELECT COUNT(*) FROM orders o2 
                INNER JOIN order_users ou5 ON ou5.id = o2.order_user_id 
                WHERE ou5.user_id = u.id) >= 10
        )`);
    } else if (category === 'disabled') {
        where.push("(u.account_status = 'disabled' OR u.locked_until IS NOT NULL)");
    }

    const whereSQL = where.length ? `WHERE ${where.join(' AND ')}` : '';

    try {
        // ??? LEFT JOIN???????????order_users ??????????????        const [rows] = await pool.execute(
            `SELECT DISTINCT
                u.id, u.phone, u.nickname, u.email, u.avatar, u.role,
                u.account_status, u.is_phone_verified, u.created_at, u.last_login_at,
                COALESCE(ou.total_orders, 0) AS total_orders, 
                COALESCE(ou.credit_score, 100) AS credit_score, 
                COALESCE(ou.timely_payments, 0) AS timely_payments,
                COALESCE(ou.completed_orders, 0) AS completed_orders,
                COALESCE(ou.total_spent, 0) AS total_spent,
                (SELECT COUNT(*) FROM orders o 
                 INNER JOIN order_users ou6 ON ou6.id = o.order_user_id 
                 WHERE ou6.user_id = u.id) AS actual_order_count,
                (SELECT COALESCE(SUM(o.final_fee), 0) FROM orders o 
                 INNER JOIN order_users ou7 ON ou7.id = o.order_user_id 
                 WHERE ou7.user_id = u.id) AS actual_total_spent
             FROM users u
             LEFT JOIN order_users ou ON ou.user_id = u.id
             ${whereSQL}
             ORDER BY u.created_at DESC
             LIMIT ? OFFSET ?`,
            [...params, Number(pageSize), offset]
        );

        const [cnt] = await pool.execute(
            `SELECT COUNT(DISTINCT u.id) AS total
             FROM users u
             ${whereSQL}`,
            params
        );

        res.json({ success: true, data: rows, total: cnt[0]?.total || 0 });
    } catch (error) {
        console.error('????????????????', error);
        res.status(500).json({ success: false, message: '???????? });
    }
});

// ????????????????????????? users ????? ?????app.post('/api/users/create-admin', async (req, res) => {
    const { phone, nickname, email, password } = req.body || {};
    if (!phone) return res.status(400).json({ success: false, message: '???????? });

    try {
        const [exist] = await pool.execute('SELECT id FROM users WHERE phone = ?', [phone]);
        if (exist.length > 0) {
            return res.json({ success: false, message: '??????????? });
        }

        const [cols] = await pool.execute('SHOW COLUMNS FROM users');
        const has = (c) => cols.some(x => x.Field === c);

        const fields = [];
        const vals = [];
        const ph = [];

        // ???
        if (has('phone')) { fields.push('phone'); vals.push(phone); ph.push('?'); }

        // ????        if (nickname !== undefined && has('nickname')) { fields.push('nickname'); vals.push(nickname || null); ph.push('?'); }
        if (email !== undefined && has('email')) { fields.push('email'); vals.push(email || null); ph.push('?'); }
        // ?????????????        if (password !== undefined && has('password_hash') && password) {
            const bcrypt = require('bcryptjs');
            const hashedPassword = await bcrypt.hash(password, 10);
            fields.push('password_hash');
            vals.push(hashedPassword);
            ph.push('?');
        } else if (password !== undefined && has('password_hash')) {
            // ???password???????????        }
        if (has('role')) { fields.push('role'); vals.push('order_user'); ph.push('?'); }
        if (has('account_status')) { fields.push('account_status'); vals.push('active'); ph.push('?'); }
        if (has('login_method')) { fields.push('login_method'); vals.push(password ? 'password' : 'sms'); ph.push('?'); }
        if (has('is_phone_verified')) { fields.push('is_phone_verified'); vals.push(0); ph.push('?'); }
        if (has('created_at')) { fields.push('created_at'); ph.push('NOW()'); }

        if (fields.length === 0) {
            return res.status(400).json({ success: false, message: 'users ?????????????? });
        }

        const valueSql = ph.map(p => (p === 'NOW()' ? 'NOW()' : '?')).join(', ');
        const sql = `INSERT INTO users (${fields.join(', ')}) VALUES (${valueSql})`;
        const [ins] = await pool.execute(sql, vals);

        // ????????????????????        try {
            const [orderCols] = await pool.execute('SHOW TABLES LIKE "order_users"');
            if (orderCols.length) {
                await pool.execute(
                    `INSERT INTO order_users (user_id, credit_score, total_orders, completed_orders, timely_payments)
                     VALUES (?, 100, 0, 0, 0)`,
                    [ins.insertId]
                );
            }
        } catch (e) { console.warn('?????order_users ???(?????:', e.message); }

        res.json({ success: true, message: '??????', data: { userId: ins.insertId } });
    } catch (error) {
        console.error('????????????????', error);
        res.status(500).json({ success: false, message: '??????: ' + error.message });
    }
});

// ??????????????app.get('/api/couriers/admin-list', async (req, res) => {
    const { page = 1, pageSize = 20, keyword = '' } = req.query || {};
    const offset = (Number(page) - 1) * Number(pageSize);

    // ??????????????????????????????    // ?????rders???courier_user_id?????????????????????????????courier_users????????    const where = [`EXISTS (
        SELECT 1 FROM orders o 
        INNER JOIN courier_users cu2 ON cu2.id = o.courier_user_id 
        WHERE cu2.user_id = u.id AND o.courier_user_id IS NOT NULL
    )`];
    const params = [];
    if (keyword) {
        where.push('(u.phone LIKE ? OR u.nickname LIKE ?)');
        params.push(`%${keyword}%`, `%${keyword}%`);
    }

    const whereSQL = where.length ? `WHERE ${where.join(' AND ')}` : '';
    try {
        // ??? LEFT JOIN???????????courier_users ??????????????        const [rows] = await pool.execute(
            `SELECT DISTINCT
                u.id, u.phone, u.nickname, u.created_at, u.account_status,
                COALESCE(cu.id, 0) AS courier_id,
                COALESCE(cu.user_id, u.id) AS user_id,
                COALESCE(cu.credit_score, 100) AS credit_score,
                COALESCE(cu.total_pickups, 0) AS total_pickups,
                COALESCE(cu.completed_pickups, 0) AS completed_pickups,
                COALESCE(cu.total_income, 0) AS total_income,
                COALESCE(cu.rating, 5.0) AS rating,
                (SELECT COUNT(*) FROM orders o 
                 INNER JOIN courier_users cu3 ON cu3.id = o.courier_user_id 
                 WHERE cu3.user_id = u.id) AS actual_pickup_count,
                (SELECT COALESCE(SUM(o.final_fee), 0) FROM orders o 
                 INNER JOIN courier_users cu4 ON cu4.id = o.courier_user_id 
                 WHERE cu4.user_id = u.id AND o.status = 5) AS actual_total_income
             FROM users u
             LEFT JOIN courier_users cu ON cu.user_id = u.id
             ${whereSQL}
             ORDER BY u.created_at DESC
             LIMIT ? OFFSET ?`,
            [...params, Number(pageSize), offset]
        );
        const [cnt] = await pool.execute(
            `SELECT COUNT(DISTINCT u.id) AS total 
             FROM users u
             ${whereSQL}`,
            params
        );
        res.json({ success: true, data: rows, total: cnt[0]?.total || 0 });
    } catch (e) {
        console.error('????????????????', e);
        res.status(500).json({ success: false, message: '???????? });
    }
});

// ???????????????????????????app.post('/api/couriers/admin-create', async (req, res) => {
    const { phone, nickname, password } = req.body || {};
    if (!phone) return res.status(400).json({ success: false, message: '???????? });
    try {
        const [exist] = await pool.execute('SELECT id FROM users WHERE phone = ?', [phone]);
        if (exist.length > 0) return res.json({ success: false, message: '??????????? });

        const [cols] = await pool.execute('SHOW COLUMNS FROM users');
        const has = (c) => cols.some(x => x.Field === c);
        const fields = []; const vals = []; const ph = [];
        if (has('phone')) { fields.push('phone'); vals.push(phone); ph.push('?'); }
        if (nickname !== undefined && has('nickname')) { fields.push('nickname'); vals.push(nickname || null); ph.push('?'); }
        // ?????????????        if (password !== undefined && has('password_hash') && password) {
            const bcrypt = require('bcryptjs');
            const hashedPassword = await bcrypt.hash(password, 10);
            fields.push('password_hash');
            vals.push(hashedPassword);
            ph.push('?');
        } else if (password !== undefined && has('password_hash')) {
            // ???password???????????        }
        // ??????? role ?????? Data truncated ???
        if (has('role')) {
            const roleCol = cols.find(c => c.Field === 'role');
            const type = (roleCol && roleCol.Type ? String(roleCol.Type) : '').toLowerCase();
            let roleValue = null;
            if (type.startsWith('enum(')) {
                const m = type.match(/enum\((.*)\)/);
                if (m && m[1]) {
                    const opts = m[1].split(',').map(s => s.trim().replace(/^'|'$/g, ''));
                    if (opts.includes('courier_user')) roleValue = 'courier_user';
                    else if (opts.includes('courier')) roleValue = 'courier';
                    else if (opts.includes('rider')) roleValue = 'rider';
                    else if (opts.length) roleValue = opts[0];
                }
            } else if (type.includes('int')) {
                // ????? ?????????????????????????????????/?????                roleValue = 2;
            }
            if (roleValue !== null) { fields.push('role'); vals.push(roleValue); ph.push('?'); }
        }
        if (has('account_status')) { fields.push('account_status'); vals.push('active'); ph.push('?'); }
        if (has('login_method')) { fields.push('login_method'); vals.push(password ? 'password' : 'sms'); ph.push('?'); }
        if (has('is_phone_verified')) { fields.push('is_phone_verified'); vals.push(0); ph.push('?'); }
        if (has('created_at')) { fields.push('created_at'); ph.push('NOW()'); }

        const valueSql = ph.map(p => (p === 'NOW()' ? 'NOW()' : '?')).join(', ');
        const sql = `INSERT INTO users (${fields.join(', ')}) VALUES (${valueSql})`;
        const [ins] = await pool.execute(sql, vals);

        // ?????courier_users????????        try {
            const [tbl] = await pool.execute('SHOW TABLES LIKE "courier_users"');
            if (tbl.length) {
                const [cCols] = await pool.execute('SHOW COLUMNS FROM courier_users');
                const hasCU = (c) => cCols.some(x => x.Field === c);
                const cFields = ['user_id'];
                const cVals = [ins.insertId];
                const cPh = ['?'];
                if (hasCU('rating')) { cFields.push('rating'); cVals.push(5.0); cPh.push('?'); }
                if (hasCU('completed_orders')) { cFields.push('completed_orders'); cVals.push(0); cPh.push('?'); }
                if (hasCU('total_income')) { cFields.push('total_income'); cVals.push(0); cPh.push('?'); }
                if (hasCU('service_range')) { cFields.push('service_range'); cVals.push(null); cPh.push('?'); }
                if (hasCU('service_time')) { cFields.push('service_time'); cVals.push(null); cPh.push('?'); }
                const sqlCU = `INSERT INTO courier_users (${cFields.join(', ')}) VALUES (${cPh.join(', ')})`;
                await pool.execute(sqlCU, cVals);
            }
        } catch (e) { console.warn('?????courier_users ???(?????:', e.message); }

        res.json({ success: true, message: '??????', data: { userId: ins.insertId } });
    } catch (e) {
        console.error('?????????????', e);
        res.status(500).json({ success: false, message: '??????: ' + e.message });
    }
});

// ????????api/users/profile/:userId ???????????
app.get('/api/users/profile/:userId', async (req, res) => {
    const { userId } = req.params;
    console.log('?? ?????????????????D:', userId);

    try {
        // ???????????* ????????????
        const [users] = await pool.execute('SELECT * FROM users WHERE id = ?', [userId]);
        if (users.length === 0) {
            return res.status(404).json({ success: false, message: '???????? });
        }
        const base = users[0] || {};
        if (!base.nickname) {
            const phone = base.phone || '';
            base.nickname = phone ? `???${String(phone).slice(-4)}` : `???${userId}`;
        }
        // ???avatar??vatar_url???????????RL
        // ??????avatar_url????????????????????????????        if (base.avatar_url) {
            base.avatar = base.avatar_url;
            base.avatar_url = base.avatar_url;
        } else if (base.avatar) {
            base.avatar_url = base.avatar;
        }
        if (!base.avatar) base.avatar = '';
        if (!base.avatar_url) base.avatar_url = '';
        if (!('role' in base)) base.role = null;

        // ????????        const [orderExt] = await pool.execute(
            'SELECT * FROM order_users WHERE user_id = ?',
            [userId]
        );
        // ????????        const [courierExt] = await pool.execute(
            'SELECT * FROM courier_users WHERE user_id = ?',
            [userId]
        );

        // ?????????????        const [cols] = await pool.execute('SHOW COLUMNS FROM users');
        const hasEmailVerified = cols.some(col => col.Field === 'email_verified');
        const emailVerified = hasEmailVerified ? (base.email_verified || 0) : null;

        res.json({
            success: true,
            data: {
                ...base,
                email_verified: emailVerified,
                order_profile: orderExt[0] || null,
                courier_profile: courierExt[0] || null
            }
        });
    } catch (error) {
        console.error('?????????????????:', error);
        res.status(500).json({ success: false, message: '???????? });
    }
});

// ???????????????????????????????????
app.get('/api/users/:userId/order-statistics', async (req, res) => {
    const { userId } = req.params;
    console.log('?? ??????????????????ID:', userId);

    try {
        // 1. ???order_user_id
        const [orderUsers] = await pool.execute(
            'SELECT id FROM order_users WHERE user_id = ?',
            [userId]
        );

        if (orderUsers.length === 0) {
            // ??????order_user?????????????            return res.json({
                success: true,
                data: {
                    completedOrders: 0,
                    inProgressOrders: 0,
                    averageRating: 5.0
                }
            });
        }

        const orderUserId = orderUsers[0].id;

        // 2. ??????????????tatus = 4 ??5??        const [completedResult] = await pool.execute(
            `SELECT COUNT(*) as count 
             FROM orders 
             WHERE order_user_id = ? AND status IN (4, 5)`,
            [orderUserId]
        );
        const completedOrders = completedResult[0]?.count || 0;

        // 3. ??????????????tatus = 2 ??3??????????????        const [inProgressResult] = await pool.execute(
            `SELECT COUNT(*) as count 
             FROM orders 
             WHERE order_user_id = ? AND status IN (2, 3)`,
            [orderUserId]
        );
        const inProgressOrders = inProgressResult[0]?.count || 0;

        // 4. ?????????
        // ???order_users????????????????????.0??        const [orderUserInfo] = await pool.execute(
            'SELECT rating FROM order_users WHERE id = ?',
            [orderUserId]
        );
        let averageRating = orderUserInfo[0]?.rating;

        // ??????rating??????null??????5.0
        if (!averageRating || averageRating === null) {
            averageRating = 5.0;
            // ?????????????????????
            try {
                await pool.execute(
                    'UPDATE order_users SET rating = 5.0 WHERE id = ?',
                    [orderUserId]
                );
            } catch (e) {
                // ??????????????????
                console.warn('???rating????????????????????', e.message);
            }
        } else {
            averageRating = parseFloat(averageRating);
        }

        // 5. ??????????????????????atings???
        try {
            const [ratingTable] = await pool.execute("SHOW TABLES LIKE 'ratings'");
            if (ratingTable.length > 0) {
                // ????????????????????????ratings???order_user_id??ating?????                // ?????????????????????ratings????????                const [ratingCols] = await pool.execute('SHOW COLUMNS FROM ratings');
                const hasOrderUserId = ratingCols.some(col => col.Field === 'order_user_id');
                const hasRating = ratingCols.some(col => col.Field === 'rating');

                if (hasOrderUserId && hasRating) {
                    const [recentRatings] = await pool.execute(
                        `SELECT rating FROM ratings 
                         WHERE order_user_id = ? 
                         ORDER BY created_at DESC LIMIT 1`,
                        [orderUserId]
                    );

                    if (recentRatings.length > 0) {
                        const latestRating = parseFloat(recentRatings[0].rating);
                        // ?????????????.0???????????                        if (latestRating < 5.0) {
                            averageRating = (averageRating + latestRating) / 2;
                            // ???order_users?????ating
                            try {
                                await pool.execute(
                                    'UPDATE order_users SET rating = ? WHERE id = ?',
                                    [averageRating, orderUserId]
                                );
                            } catch (e) {
                                console.warn('???rating???:', e.message);
                            }
                        }
                    }
                }
            }
        } catch (e) {
            console.warn('????atings?????', e.message);
        }

        res.json({
            success: true,
            data: {
                completedOrders: completedOrders,
                inProgressOrders: inProgressOrders,
                averageRating: parseFloat(averageRating.toFixed(1))
            }
        });

    } catch (error) {
        console.error('???????????????????', error);
        res.status(500).json({
            success: false,
            message: '????????????: ' + error.message
        });
    }
});

// ??????????????????/?????????"??????"???
app.put('/api/users/profile/:userId', async (req, res) => {
    const { userId } = req.params;
    const body = req.body || {};
    console.log('??? ?????????', { userId, body });

    const conn = await pool.getConnection();
    try {
        await conn.beginTransaction();
        // ???????users ?????? phone/email/nickname/avatar_url ???
        const [userCols] = await conn.execute('SHOW COLUMNS FROM users');
        const hasU = (c) => userCols.some(x => x.Field === c);
        const uUpdates = [];
        const uParams = [];

        // ??? phone?????????????????????????
        if ('phone' in body && hasU('phone') && body.phone) {
            // ???????????????????????
            const [existingUsers] = await conn.execute(
                'SELECT id FROM users WHERE phone = ? AND id != ?',
                [body.phone, userId]
            );
            if (existingUsers.length > 0) {
                await conn.rollback();
                return res.status(400).json({
                    success: false,
                    message: '????????????????????????????????
                });
            }
            uUpdates.push('phone = ?');
            uParams.push(body.phone);
        }
        // ??? email????????????????????
        // ?????????email_verified??rue??????????????????????????????
        if ('email' in body && hasU('email') && body.email) {
            // ??????????            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
            if (!emailRegex.test(body.email)) {
                await conn.rollback();
                return res.status(400).json({
                    success: false,
                    message: '???????????
                });
            }
            // ??????email_verified??????????????            if (hasU('email_verified')) {
                uUpdates.push('email = ?, email_verified = 0');
                uParams.push(body.email);
            } else {
                uUpdates.push('email = ?');
                uParams.push(body.email);
            }
        }
        // ??? nickname????????????
        if ('nickname' in body && hasU('nickname')) {
            uUpdates.push('nickname = ?');
            uParams.push(body.nickname || null);
        }
        // ??? avatar_url???????????????base64?????        if ('avatar_url' in body && hasU('avatar_url')) {
            uUpdates.push('avatar_url = ?');
            uParams.push(body.avatar_url || null);
        }
        // ???avatar???????????vatar_url?????        if ('avatar' in body && !hasU('avatar_url') && hasU('avatar')) {
            uUpdates.push('avatar = ?');
            uParams.push(body.avatar || null);
        }

        // ???????????? SQL
        if (uUpdates.length) {
            // ???????? last_action_at ?????????????????????
            if (hasU('last_action_at')) {
                uUpdates.push('last_action_at = NOW()');
            }
            uParams.push(userId);
            await conn.execute(`UPDATE users SET ${uUpdates.join(', ')} WHERE id = ?`, uParams);
            console.log('??users ????????', uUpdates.join(', '));
        }

        // ???????order_users?????????
        const [ouCols] = await conn.execute('SHOW COLUMNS FROM order_users');
        const hasO = (c) => ouCols.some(x => x.Field === c);

        // ???????????
        const [existingOU] = await conn.execute('SELECT id FROM order_users WHERE user_id = ?', [userId]);

        if (existingOU.length === 0) {
            // ???????????????????????????100
            const oFields = ['user_id'];
            const oValues = [userId];
            if (hasO('credit_score')) {
                oFields.push('credit_score');
                oValues.push(100);
            }
            if ('college' in body && hasO('college')) { oFields.push('college'); oValues.push(body.college || null); }
            if ('major' in body && hasO('major')) { oFields.push('major'); oValues.push(body.major || null); }
            if ('student_id' in body && hasO('student_id')) { oFields.push('student_id'); oValues.push(body.student_id || null); }
            if ('dorm_building' in body && hasO('dorm_building')) { oFields.push('dorm_building'); oValues.push(body.dorm_building || null); }
            if ('dorm_room' in body && hasO('dorm_room')) { oFields.push('dorm_room'); oValues.push(body.dorm_room || null); }
            if (oFields.length > 0) {
                const placeholders = oFields.map(() => '?');
                const sql = `INSERT INTO order_users (${oFields.join(',')}) VALUES (${placeholders.join(',')})`;
                await conn.execute(sql, oValues);
                console.log('??order_users ?????????????????00');
            }
        } else {
            // ??????????????????credit_score??            const oFields = ['user_id'];
            const oValues = [userId];
            const oUpdates = [];
            if ('college' in body && hasO('college')) { oFields.push('college'); oValues.push(body.college || null); oUpdates.push('college=VALUES(college)'); }
            if ('major' in body && hasO('major')) { oFields.push('major'); oValues.push(body.major || null); oUpdates.push('major=VALUES(major)'); }
            if ('student_id' in body && hasO('student_id')) { oFields.push('student_id'); oValues.push(body.student_id || null); oUpdates.push('student_id=VALUES(student_id)'); }
            if ('dorm_building' in body && hasO('dorm_building')) { oFields.push('dorm_building'); oValues.push(body.dorm_building || null); oUpdates.push('dorm_building=VALUES(dorm_building)'); }
            if ('dorm_room' in body && hasO('dorm_room')) { oFields.push('dorm_room'); oValues.push(body.dorm_room || null); oUpdates.push('dorm_room=VALUES(dorm_room)'); }
            if (oFields.length > 1 && oUpdates.length > 0) {
                const placeholders = oFields.map(() => '?');
                const sql = `INSERT INTO order_users (${oFields.join(',')}) VALUES (${placeholders.join(',')})
                         ON DUPLICATE KEY UPDATE ${oUpdates.join(', ')}`;
                await conn.execute(sql, oValues);
                console.log('??order_users ????????);
            }
        }

        // ???????courier_users??????????????        try {
            const [cuTable] = await conn.execute('SHOW TABLES LIKE "courier_users"');
            if (cuTable.length > 0) {
                const [cuCols] = await conn.execute('SHOW COLUMNS FROM courier_users');
                const hasC = (c) => cuCols.some(x => x.Field === c);
                const cFields = ['user_id'];
                const cValues = [userId];
                const cUpdates = [];
                if ('service_range' in body && hasC('service_range')) { cFields.push('service_range'); cValues.push(body.service_range || null); cUpdates.push('service_range=VALUES(service_range)'); }
                if ('service_time' in body && hasC('service_time')) { cFields.push('service_time'); cValues.push(body.service_time || null); cUpdates.push('service_time=VALUES(service_time)'); }
                if (cFields.length > 1) {
                    const placeholders = cFields.map((_, i) => i === 0 ? '?' : '?');
                    const sql = `INSERT INTO courier_users (${cFields.join(',')}) VALUES (${placeholders.join(',')})
                                 ON DUPLICATE KEY UPDATE ${cUpdates.join(', ')}`;
                    await conn.execute(sql, cValues);
                    console.log('??courier_users ????????);
                }
            }
        } catch (e) {
            console.warn('??? courier_users ???(?????:', e.message);
        }

        await conn.commit();

        // ?????????????????????????????????
        try {
            const currentUserId = req.user?.userId || userId;
            const [userCheck] = await pool.execute(
                'SELECT role FROM users WHERE id = ? AND role = ?',
                [currentUserId, 'admin']
            );
            if (userCheck.length > 0) {
                await pool.execute(
                    `INSERT INTO admin_operation_logs (admin_id, operation_type, target_type, target_id, operation_details, ip_address, user_agent)
                 VALUES (?, ?, 'user', ?, ?, ?, ?)`,
                    [currentUserId, 'update_user_profile', userId, JSON.stringify(body || {}), req.ip, req.headers['user-agent']]
                );
            }
        } catch (e) { console.warn('????????????(?????:', e.message); }

        res.json({ success: true, message: '??????' });
    } catch (error) {
        await conn.rollback();
        console.error('???????????:', error);
        res.status(500).json({ success: false, message: '???????? });
    } finally {
        conn.release();
    }
});

// ???????????????app.get('/api/users/check-phone', async (req, res) => {
    const { userId } = req.query;
    console.log('?? ?????????????????ID:', userId);

    try {
        const [users] = await pool.execute(
            'SELECT id, is_phone_verified FROM users WHERE id = ?',
            [userId]
        );

        if (users.length === 0) {
            return res.json({
                success: false,
                message: '????????
            });
        }

        res.json({
            success: true,
            data: {
                isPhoneVerified: users[0].is_phone_verified
            }
        });
    } catch (error) {
        console.error('??????????????????', error);
        res.json({
            success: false,
            message: '???????
        });
    }
});

// ?????????
app.get('/api/users/order-users/credit/:userId', async (req, res) => {
    const { userId } = req.params;
    console.log('?? ??????????????D:', userId);

    res.json({
        success: true,
        data: {
            credit: 100,
            level: '???'
        }
    });
});

// ========== ????????? ==========

// ??????????????????
app.get('/api/orders/user/:userId', async (req, res) => {
    const { userId } = req.params;
    console.log('?? ??????????????D:', userId);
    try {
        const [orderCols] = await pool.execute('SHOW COLUMNS FROM orders');
        const has = (c) => orderCols.some(x => x.Field === c);
        const userCol = has('order_user_id') ? 'order_user_id' : (has('order_user') ? 'order_user' : (has('user_id') ? 'user_id' : null));
        if (!userCol) return res.json({ success: true, data: [] });

        // ????????????????????????? SQL ??????
        const courierCol = has('courier_user_id') ? 'courier_user_id' : (has('courier_user') ? 'courier_user' : null);
        const selectFields = [
            'id',
            `${userCol} AS order_user_id`,
            courierCol ? `${courierCol} AS courier_user_id` : 'NULL AS courier_user_id',
            has('pickup_location') ? 'pickup_location' : 'NULL AS pickup_location',
            has('pickup_code') ? 'pickup_code' : "NULL AS pickup_code",
            has('delivery_address') ? 'delivery_address' : 'NULL AS delivery_address',
            has('status') ? 'status' : 'NULL AS status',
            has('note') ? 'note' : 'NULL AS note',
            has('created_at') ? 'created_at' : 'NOW() AS created_at'
        ];
        const feeCols = [];
        if (has('final_fee')) feeCols.push('final_fee');
        if (has('suggested_fee')) feeCols.push('suggested_fee');
        if (has('fee')) feeCols.push('fee');
        if (has('amount')) feeCols.push('amount');
        if (feeCols.length) selectFields.splice(6, 0, `COALESCE(${feeCols.join(', ')}, 0) AS fee`);
        else selectFields.splice(6, 0, '0 AS fee');

        const orderBy = has('created_at') ? 'created_at' : 'id';
        const sql = `SELECT ${selectFields.join(', ')} FROM orders WHERE ${userCol} = ? ORDER BY ${orderBy} DESC`;
        const [rows] = await pool.execute(sql, [userId]);

        const data = rows.map(r => {
            // ??? status ????????            const statusValue = r.status != null ? Number(r.status) : 1;
            return {
                id: r.id,
                status: statusValue, // ????????????????                title: r.pickup_code ? `??????${r.pickup_code}` : '????????,
                desc: r.note || `${r.pickup_location || ''} ??${r.delivery_address || ''}`.trim(),
                amount: Number(r.fee || 0).toFixed(2),
                time: (r.created_at && String(r.created_at).replace('T', ' ').slice(0, 19)) || '',
                courier_user_id: r.courier_user_id || null
            };
        });

        res.json({ success: true, data });
    } catch (e) {
        console.error('??????????????:', e);
        res.status(500).json({ success: false, message: '???????? });
    }
});

// ??? ?????????????????? orderRoutes.js ????????????
// ????????????????????? backend/routes/orderRoutes.js
// ??app.js ?????????????????? orderRoutes.js

// ????????????????????????/??????
app.get('/api/orders', async (req, res) => {
    const { status, startDate, endDate, courier, keyword, page = 1, pageSize = 20 } = req.query || {};
    console.log('?? ?????????(????:', { status, startDate, endDate, courier, keyword, page, pageSize });

    // ????????1 ????? 2 ?????, 3 ????? 4 ?????    const statusMap = {
        '?????: 1,
        '?????': 2,
        '?????: 3,
        '?????: 4
    };

    const whereClauses = [];
    const params = [];

    if (status && statusMap[status]) {
        whereClauses.push('o.status = ?');
        params.push(statusMap[status]);
    }

    // ???????????yyyy/mm/dd ??yyyy-mm-dd ???
    const norm = (s) => (s || '').replaceAll('/', '-');
    if (startDate) {
        whereClauses.push('o.created_at >= ?');
        params.push(`${norm(startDate)} 00:00:00`);
    }
    if (endDate) {
        whereClauses.push('o.created_at <= ?');
        params.push(`${norm(endDate)} 23:59:59`);
    }

    if (courier) {
        // ?????????????????????
        whereClauses.push('(cu.nickname LIKE ? OR cu.phone LIKE ?)');
        params.push(`%${courier}%`, `%${courier}%`);
    }

    if (keyword) {
        whereClauses.push('(o.id LIKE ? OR o.pickup_location LIKE ? OR o.delivery_address LIKE ? OR u.phone LIKE ? OR cu.phone LIKE ?)');
        params.push(`%${keyword}%`, `%${keyword}%`, `%${keyword}%`, `%${keyword}%`, `%${keyword}%`);
    }

    const whereSQL = whereClauses.length ? `WHERE ${whereClauses.join(' AND ')}` : '';

    const offset = (Number(page) - 1) * Number(pageSize);

    try {
        // ????????order_user_id / courier_user_id??        const [orderCols] = await pool.execute('SHOW COLUMNS FROM orders');
        const has = (c) => orderCols.some(x => x.Field === c);
        const orderUserCol = has('order_user_id') ? 'order_user_id' : (has('order_user') ? 'order_user' : null);
        const courierUserCol = has('courier_user_id') ? 'courier_user_id' : (has('courier_user') ? 'courier_user' : null);

        const joinOrder = orderUserCol ? `LEFT JOIN users u ON o.${orderUserCol} = u.id` : 'LEFT JOIN users u ON 1=0';
        const joinCourier = courierUserCol ? `LEFT JOIN users cu ON o.${courierUserCol} = cu.id` : 'LEFT JOIN users cu ON 1=0';

        const rowsSql =
            `SELECT 
                o.id,
                ${orderUserCol ? `o.${orderUserCol}` : 'NULL'} AS order_user_id,
                ${courierUserCol ? `o.${courierUserCol}` : 'NULL'} AS courier_user_id,
                o.pickup_location,
                o.delivery_address,
                o.suggested_fee,
                o.final_fee,
                o.status,
                o.created_at,
                u.nickname AS order_user_nickname,
                u.phone    AS order_user_phone,
                cu.nickname AS courier_nickname,
                cu.phone    AS courier_phone
             FROM orders o
             ${joinOrder}
             ${joinCourier}
             ${whereSQL}
             ORDER BY o.created_at DESC
             LIMIT ${Number(pageSize)} OFFSET ${offset}`;
        const [rows] = await pool.execute(rowsSql, params);

        // ??????
        const cntSql =
            `SELECT COUNT(*) AS total
             FROM orders o
             ${joinOrder}
             ${joinCourier}
             ${whereSQL}`;
        const [cntRows] = await pool.execute(cntSql, params);

        res.json({ success: true, data: rows, total: cntRows[0]?.total || 0 });
    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '???????? });
    }
});

// ??? ??????/api/orders/available ?????? orderRoutes.js ?????// ????????????????????
// ??????
app.get('/api/orders/:id', async (req, res) => {
    const { id } = req.params;
    console.log('?? ?????????:', id);
    try {
        const [orderCols] = await pool.execute('SHOW COLUMNS FROM orders');
        const has = (c) => orderCols.some(x => x.Field === c);
        const orderUserCol = has('order_user_id') ? 'order_user_id' : (has('order_user') ? 'order_user' : null);
        const courierUserCol = has('courier_user_id') ? 'courier_user_id' : (has('courier_user') ? 'courier_user' : null);

        const joinOrder = orderUserCol ? `LEFT JOIN users u ON o.${orderUserCol} = u.id` : 'LEFT JOIN users u ON 1=0';
        const joinCourier = courierUserCol ? `LEFT JOIN users cu ON o.${courierUserCol} = cu.id` : 'LEFT JOIN users cu ON 1=0';

        const [rows] = await pool.execute(
            `SELECT o.*, u.phone AS order_user_phone, u.nickname AS order_user_nickname,
                    cu.phone AS courier_phone, cu.nickname AS courier_nickname
             FROM orders o
             ${joinOrder}
             ${joinCourier}
             WHERE o.id = ?`,
            [id]
        );
        if (rows.length === 0) return res.status(404).json({ success: false, message: '???????? });
        res.json({ success: true, data: rows[0] });
    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '???????? });
    }
});

// ?????????????????app.put('/api/orders/:id', async (req, res) => {
    const { id } = req.params;
    const allowFields = [
        'status', 'courier_user', 'pickup_location', 'delivery_address', 'suggested_fee', 'final_fee',
        'note', 'express_company', 'express_type', 'package_size', 'package_weight'
    ];
    const updates = [];
    const params = [];

    // ??????????-> ???
    const statusMap = { '?????: 1, '?????': 2, '?????: 3, '?????: 4 };

    for (const key of allowFields) {
        if (Object.prototype.hasOwnProperty.call(req.body || {}, key)) {
            if (key === 'status' && typeof req.body[key] === 'string' && statusMap[req.body[key]]) {
                updates.push('status = ?');
                params.push(statusMap[req.body[key]]);
            } else if (key === 'courier_user') {
                // ???????courier ??????????????users.id ?????courier_users.id
                const [orderCols] = await pool.execute('SHOW COLUMNS FROM orders');
                const has = (c) => orderCols.some(x => x.Field === c);
                const courierCol = has('courier_user_id') ? 'courier_user_id' : (has('courier_user') ? 'courier_user' : null);
                if (courierCol) {
                    if (courierCol === 'courier_user_id') {
                        // ?????????ID?????courier_users.id
                        const userIdVal = req.body[key];
                        try {
                            const [exists] = await pool.execute('SELECT id FROM courier_users WHERE user_id = ? LIMIT 1', [userIdVal]);
                            let courierProfileId = exists[0]?.id;
                            if (!courierProfileId) {
                                // ?????????????                                const [cCols] = await pool.execute('SHOW COLUMNS FROM courier_users');
                                const hasC = (n) => cCols.some(x => x.Field === n);
                                if (!hasC('user_id')) throw new Error('courier_users ??? user_id ??);
                                const cols = ['user_id'];
                                const phs = ['?'];
                                const vals = [userIdVal];
                                // ????????????100
                                if (hasC('credit_score')) {
                                    cols.push('credit_score');
                                    phs.push('?');
                                    vals.push(100);
                                }
                                // ???????????                                if (hasC('created_at')) { cols.push('created_at'); phs.push('NOW()'); }
                                if (hasC('updated_at')) { cols.push('updated_at'); phs.push('NOW()'); }
                                const sql = `INSERT INTO courier_users (${cols.join(',')}) VALUES (${phs.join(',')})`;
                                const [ins] = await pool.execute(sql, vals);
                                courierProfileId = ins.insertId;
                            }
                            updates.push(`${courierCol} = ?`);
                            params.push(courierProfileId);
                        } catch (e) {
                            return res.status(400).json({ success: false, message: '???????????????????? ' + e.message });
                        }
                    } else {
                        updates.push(`${courierCol} = ?`);
                        params.push(req.body[key]);
                    }
                }
            } else {
                updates.push(`${key} = ?`);
                params.push(req.body[key]);
            }
        }
    }

    if (updates.length === 0) return res.status(400).json({ success: false, message: '?????????' });

    try {
        params.push(id);
        const [r] = await pool.execute(
            `UPDATE orders SET ${updates.join(', ')}, updated_at = NOW() WHERE id = ?`,
            params
        );
        if (r.affectedRows === 0) return res.status(404).json({ success: false, message: '???????? });

        // ???????????operation_type/operation_details??        // ?????????????????????????????????
        try {
            const currentUserId = req.user?.userId;
            if (currentUserId) {
                const [userCheck] = await pool.execute(
                    'SELECT role FROM users WHERE id = ? AND role = ?',
                    [currentUserId, 'admin']
                );
                if (userCheck.length > 0) {
                    await pool.execute(
                        `INSERT INTO admin_operation_logs (admin_id, operation_type, target_type, target_id, operation_details, ip_address, user_agent)
                 VALUES (?, ?, 'order', ?, ?, ?, ?)`,
                        [currentUserId, 'update_order', id, JSON.stringify(req.body || {}), req.ip, req.headers['user-agent']]
                    );
                }
            }
        } catch (e) { console.warn('????????????(?????:', e.message); }

        res.json({ success: true, message: '??????' });
    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({ success: false, message: '???????? });
    }
});

// ????????app.post('/api/orders/:id/accept', async (req, res) => {
    const { id } = req.params;
    const { courier_user } = req.body || {};
    console.log('?? ??????:', { id, courier_user });
    if (!courier_user) return res.status(400).json({ success: false, message: '????????D' });
    try {
        const [orderCols] = await pool.execute('SHOW COLUMNS FROM orders');
        const has = (c) => orderCols.some(x => x.Field === c);
        const courierCol = has('courier_user_id') ? 'courier_user_id' : (has('courier_user') ? 'courier_user' : null);
        const statusCol = has('status') ? 'status' : null;
        const statusColType = orderCols.find(x => x.Field === 'status')?.Type || '';
        const statusIsNumeric = /(int|decimal|bigint|tinyint|float|double)/i.test(statusColType);
        const statusValue = statusIsNumeric ? 2 : '?????';
        let valueToSet = courier_user;
        if (courierCol === 'courier_user_id') {
            // ??users.id ?????courier_users.id
            const [exists] = await pool.execute('SELECT id FROM courier_users WHERE user_id = ? LIMIT 1', [courier_user]);
            let courierProfileId = exists[0]?.id;
            if (!courierProfileId) {
                const [cCols] = await pool.execute('SHOW COLUMNS FROM courier_users');
                const hasC = (n) => cCols.some(x => x.Field === n);
                if (!hasC('user_id')) throw new Error('courier_users ??? user_id ??);
                const cols = ['user_id'];
                const phs = ['?'];
                const vals = [courier_user];
                // ????????????100
                if (hasC('credit_score')) {
                    cols.push('credit_score');
                    phs.push('?');
                    vals.push(100);
                }
                if (hasC('created_at')) { cols.push('created_at'); phs.push('NOW()'); }
                if (hasC('updated_at')) { cols.push('updated_at'); phs.push('NOW()'); }
                const sql = `INSERT INTO courier_users (${cols.join(',')}) VALUES (${phs.join(',')})`;
                const [ins] = await pool.execute(sql, vals);
                courierProfileId = ins.insertId;
            }
            valueToSet = courierProfileId;
        }
        const [r] = await pool.execute(
            `UPDATE orders SET ${courierCol} = ?, ${statusCol || 'status'} = ?, accepted_at = NOW(), updated_at = NOW() WHERE id = ?`,
            [valueToSet, statusValue, id]
        );
        if (r.affectedRows === 0) return res.status(404).json({ success: false, message: '???????? });

        // ??????
        try {
            await pool.execute(
                `INSERT INTO admin_operation_logs (admin_id, operation_type, target_id, target_type, operation_details, ip_address, user_agent)
                 VALUES (?, ?, ?, 'order', ?, ?, ?)`,
                [0, 'accept_order', id, JSON.stringify({ courier_user }), req.ip, req.headers['user-agent']]
            );
        } catch (e) { console.warn('????????????(?????:', e.message); }

        res.json({ success: true, message: '??????' });
    } catch (error) {
        console.error('????????:', error);
        res.status(500).json({ success: false, message: '???????? });
    }
});

// ???????????????????6??app.post('/api/orders/:id/cancel-by-courier', async (req, res) => {
    const { id } = req.params;
    const { courier_user } = req.body || {};
    console.log('?? ?????????:', { id, courier_user });
    if (!courier_user) return res.status(400).json({ success: false, message: '????????D' });
    try {
        const [orderCols] = await pool.execute('SHOW COLUMNS FROM orders');
        const has = (c) => orderCols.some(x => x.Field === c);
        const courierCol = has('courier_user_id') ? 'courier_user_id' : (has('courier_user') ? 'courier_user' : null);
        const statusColType = orderCols.find(x => x.Field === 'status')?.Type || '';
        const statusIsNumeric = /(int|decimal|bigint|tinyint|float|double)/i.test(statusColType);
        const cancelValue = statusIsNumeric ? 6 : '?????;
        if (!courierCol) return res.status(400).json({ success: false, message: '?????????????? });

        // ?????users.id ?????courier_users.id?????? courier_user_id ???
        let filterValue = courier_user;
        if (courierCol === 'courier_user_id') {
            const [exists] = await pool.execute('SELECT id FROM courier_users WHERE user_id = ? LIMIT 1', [courier_user]);
            if (!exists.length) return res.status(403).json({ success: false, message: '???????????????????? });
            filterValue = exists[0].id;
        }

        // ????????????????????????
        const [r] = await pool.execute(
            `UPDATE orders SET status = ?, updated_at = NOW() WHERE id = ? AND ${courierCol} = ?`,
            [cancelValue, id, filterValue]
        );
        if (r.affectedRows === 0) return res.status(403).json({ success: false, message: '??????????????????????????????' });

        try {
            await pool.execute(
                `INSERT INTO admin_operation_logs (admin_id, operation_type, target_id, target_type, operation_details, ip_address, user_agent)
                 VALUES (?, ?, ?, 'order', ?, ?, ?)`,
                [0, 'courier_cancel_order', id, JSON.stringify({ courier_user }), req.ip, req.headers['user-agent']]
            );
        } catch (e) { console.warn('????????????(?????:', e.message); }

        res.json({ success: true, message: '???????? });
    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({ success: false, message: '?????????: ' + error.message });
    }
});

// ?????????
app.get('/api/orders/stats/:userId', async (req, res) => {
    const { userId } = req.params;
    console.log('?? ??????????????D:', userId);

    res.json({
        success: true,
        data: {
            total: 0,
            completed: 0,
            pending: 0,
            canceled: 0
        }
    });
});


// ????????????????????app.get('/api/orders/courier/:courierId', async (req, res) => {
    const { courierId } = req.params;
    console.log('?? ?????????????????D:', courierId);
    try {
        const [cols] = await pool.execute('SHOW COLUMNS FROM orders');
        const has = (c) => cols.some(x => x.Field === c);
        const feeExpr = has('final_fee') ? 'final_fee' : (has('suggested_fee') ? 'suggested_fee' : '0');
        const courierCol = has('courier_user_id') ? 'courier_user_id' : (has('courier_user') ? 'courier_user' : null);
        const timeCol = has('pickup_time') ? 'pickup_time' : (has('created_at') ? 'created_at' : 'NOW()');
        if (!courierCol) return res.json({ success: true, data: [] });

        let filterValue = courierId;
        if (courierCol === 'courier_user_id') {
            // ??users.id ??? courier_users.id
            const [exists] = await pool.execute('SELECT id FROM courier_users WHERE user_id = ? LIMIT 1', [courierId]);
            if (!exists.length) return res.json({ success: true, data: [] });
            filterValue = exists[0].id;
        }

        const hasPickupCode = has('pickup_code');
        const sql = `
            SELECT id,
                   ${hasPickupCode ? 'pickup_code,' : ''}
                   pickup_location,
                   delivery_address,
                   ${feeExpr} AS fee,
                   status,
                   ${timeCol} AS time,
                   created_at
            FROM orders
            WHERE ${courierCol} = ?
            ORDER BY created_at DESC
            LIMIT 200`;
        const [rows] = await pool.execute(sql, [filterValue]);
        res.json({ success: true, data: rows });
    } catch (e) {
        console.error('????????????????', e);
        res.status(500).json({ success: false, message: '?????????????? ' + e.message });
    }
});

// ========== ??????????????? ==========

// ????????????????????????
const WECHAT_APPID = process.env.WECHAT_APPID || 'wx54b1ff4f56dfa185';
const WECHAT_SECRET = process.env.WECHAT_SECRET || '10845bc5eb0cda810f6ba3e8f841ebcc';
const WECHAT_AUTH_TYPE = process.env.WECHAT_AUTH_TYPE || 'mp'; // 'mp' = ????? 'open' = ???????
// ??????????????????????????????????????const FRONTEND_URL = process.env.FRONTEND_URL || 'http://localhost:5180';
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:5000';
const WECHAT_REDIRECT_URI = process.env.WECHAT_REDIRECT_URI || `${BACKEND_URL}/api/auth/wechat/callback`;

// ??????
if (!WECHAT_APPID || !WECHAT_SECRET) {
    console.warn('??? ???????????????????????????????WECHAT_APPID ??WECHAT_SECRET');
}

const isMpAuth = WECHAT_AUTH_TYPE === 'mp'; // ??????????????
console.log(`?? ???${isMpAuth ? '????? : '???????}???:`);
console.log('   AppID:', WECHAT_APPID);
console.log('   AppSecret:', WECHAT_SECRET ? '***' : '?????);
console.log('   ??????:', isMpAuth ? '??????????? : '?????????????);
console.log('   ??????:', WECHAT_REDIRECT_URI);
console.log('   ??????:', FRONTEND_URL);

// ????????oken????????????????????????Redis???
const qrCodeTokens = new Map();

// ??????????????app.post('/api/auth/wechat/qrcode', async (req, res) => {
    console.log('?? ??????????????);
    try {
        // ????????tate????????SRF?????        const state = 'wechat_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);

        // ??????????RL
        // ???????????? oauth2/authorize??????????????        // ?????????????? qrconnect??????????        const encodedRedirectUri = encodeURIComponent(WECHAT_REDIRECT_URI);
        let qrCodeUrl;

        if (isMpAuth) {
            // ????????????????????????????            // scope: snsapi_base???????????????openid??? snsapi_userinfo?????????????????????
            qrCodeUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${WECHAT_APPID}&redirect_uri=${encodedRedirectUri}&response_type=code&scope=snsapi_userinfo&state=${state}#wechat_redirect`;
        } else {
            // ??????????????????????            qrCodeUrl = `https://open.weixin.qq.com/connect/qrconnect?appid=${WECHAT_APPID}&redirect_uri=${encodedRedirectUri}&response_type=code&scope=snsapi_login&state=${state}#wechat_redirect`;
        }

        console.log('?? ?????????URL??edirect_uri??????:', {
            original: WECHAT_REDIRECT_URI,
            encoded: encodedRedirectUri,
            fullUrl: qrCodeUrl.replace(encodedRedirectUri, '[????????????]')
        });

        // ???state?????waiting: ??????, scanned: ????? confirmed: ????? expired: ??????
        qrCodeTokens.set(state, {
            status: 'waiting',
            createdAt: new Date(),
            userId: null,
            userInfo: null
        });

        // ????????????????        setTimeout(() => {
            const data = qrCodeTokens.get(state);
            if (data && data.status === 'waiting') {
                data.status = 'expired';
            }
        }, 5 * 60 * 1000);

        res.json({
            success: true,
            data: {
                token: state,
                qrCodeUrl: qrCodeUrl,
                expiresIn: 300 // 5???
            }
        });
    } catch (e) {
        console.error('?????????????', e);
        res.status(500).json({ success: false, message: '??????????? ' + e.message });
    }
});

// ???????????????????????app.get('/api/auth/wechat/callback', async (req, res) => {
    const { code, state } = req.query;
    console.log('?? ????????ode:', code, 'state:', state);

    if (!code || !state) {
        const errorMsg = encodeURIComponent('?????????????????????code??tate??);
        return res.redirect(`${FRONTEND_URL}/login?error=${errorMsg}`);
    }

    try {
        const tokenData = qrCodeTokens.get(state);
        if (!tokenData) {
            const errorMsg = encodeURIComponent('????????????????????????');
            return res.redirect(`${FRONTEND_URL}/login?error=${errorMsg}`);
        }

        // ???code???access_token??????????????????????????        const tokenResponse = await axios.get('https://api.weixin.qq.com/sns/oauth2/access_token', {
            params: {
                appid: WECHAT_APPID,
                secret: WECHAT_SECRET,
                code: code,
                grant_type: 'authorization_code'
            }
        });

        if (tokenResponse.data.errcode) {
            console.error('?????access_token???:', tokenResponse.data);
            const errorMsg = encodeURIComponent(`??????token?????{tokenResponse.data.errmsg || '??????'}????????{tokenResponse.data.errcode}??);
            return res.redirect(`${FRONTEND_URL}/login?error=${errorMsg}`);
        }

        const { access_token, openid } = tokenResponse.data;
        console.log('?????access_token?????penid:', openid);

        // ???access_token?????????
        const userInfoResponse = await axios.get('https://api.weixin.qq.com/sns/userinfo', {
            params: {
                access_token: access_token,
                openid: openid
            }
        });

        if (userInfoResponse.data.errcode) {
            console.error('??????????????:', userInfoResponse.data);
            // ?????????????????????openid???
            const userInfo = {
                openid: openid,
                nickname: '??????',
                avatar: '',
                gender: 0
            };
            await processWechatUser(openid, userInfo, tokenData);
        } else {
            const userInfo = userInfoResponse.data;
            console.log('??????????????:', userInfo);
            await processWechatUser(openid, userInfo, tokenData);
        }

        // processWechatUser ???????????? 'confirmed'??????????????

        // ???????????????success?????        res.redirect(`${FRONTEND_URL}/login?wechat_success=true&state=${state}`);
    } catch (e) {
        console.error('??????????????:', e);
        const errorMsg = encodeURIComponent(`??????????????{e.message}`);
        res.redirect(`${FRONTEND_URL}/login?error=${errorMsg}`);
    }
});

// ?????????????????async function processWechatUser(openid, wechatUserInfo, tokenData) {
    try {
        const [cols] = await pool.execute('SHOW COLUMNS FROM users');
        const hasOpenid = cols.some(x => x.Field === 'openid');
        const hasWechatOpenid = cols.some(x => x.Field === 'wechat_openid');
        const hasNickname = cols.some(x => x.Field === 'nickname');
        const hasAvatar = cols.some(x => x.Field === 'avatar' || x.Field === 'avatar_url');

        let userId = null;

        // ?????????
        if (hasOpenid) {
            const [users] = await pool.execute('SELECT id FROM users WHERE openid = ?', [openid]);
            if (users.length > 0) {
                userId = users[0].id;
            }
        } else if (hasWechatOpenid) {
            const [users] = await pool.execute('SELECT id FROM users WHERE wechat_openid = ?', [openid]);
            if (users.length > 0) {
                userId = users[0].id;
            }
        }

        // ????????????????????        if (!userId) {
            const insertFields = ['role', 'login_method', 'created_at'];
            const insertValues = ['order_user', 'wechat', new Date()];

            if (hasOpenid) {
                insertFields.push('openid');
                insertValues.push(openid);
            } else if (hasWechatOpenid) {
                insertFields.push('wechat_openid');
                insertValues.push(openid);
            }

            if (hasNickname && wechatUserInfo.nickname) {
                insertFields.push('nickname');
                insertValues.push(wechatUserInfo.nickname);
            }

            if (hasAvatar && wechatUserInfo.headimgurl) {
                const avatarField = cols.find(x => x.Field === 'avatar' || x.Field === 'avatar_url')?.Field;
                if (avatarField) {
                    insertFields.push(avatarField);
                    insertValues.push(wechatUserInfo.headimgurl);
                }
            }

            const placeholders = insertFields.map(() => '?').join(', ');
            const [result] = await pool.execute(
                `INSERT INTO users (${insertFields.join(', ')}) VALUES (${placeholders})`,
                insertValues
            );
            userId = result.insertId;
            console.log('??????????????ID:', userId);
        } else {
            console.log('????????????????D:', userId);
            // ??????????????????????            const updates = [];
            const updateValues = [];
            if (hasNickname && wechatUserInfo.nickname) {
                updates.push('nickname = ?');
                updateValues.push(wechatUserInfo.nickname);
            }
            if (hasAvatar && wechatUserInfo.headimgurl) {
                const avatarField = cols.find(x => x.Field === 'avatar' || x.Field === 'avatar_url')?.Field;
                if (avatarField) {
                    updates.push(`${avatarField} = ?`);
                    updateValues.push(wechatUserInfo.headimgurl);
                }
            }
            if (updates.length > 0) {
                updateValues.push(userId);
                await pool.execute(`UPDATE users SET ${updates.join(', ')} WHERE id = ?`, updateValues);
            }
        }

        // ???????????okenData
        tokenData.userId = userId;
        tokenData.userInfo = {
            nickname: wechatUserInfo.nickname || '??????',
            avatar: wechatUserInfo.headimgurl || '',
            openid: openid
        };
        tokenData.status = 'confirmed';
    } catch (e) {
        console.error('??????????????:', e);
        throw e;
    }
}

// ?????????????app.get('/api/auth/wechat/check', async (req, res) => {
    const { token } = req.query;
    console.log('?? ??????????????token:', token);

    if (!token) {
        return res.status(400).json({ success: false, message: '???token???' });
    }

    try {
        const data = qrCodeTokens.get(token);

        if (!data) {
            return res.json({
                success: false,
                message: '???????????????'
            });
        }

        // ????????????
        if (data.status === 'expired') {
            return res.json({
                success: true,
                data: {
                    status: 'expired'
                }
            });
        }

        // ??????????????????        if (data.status === 'waiting') {
            const now = new Date();
            const elapsed = now - data.createdAt;
            if (elapsed > 5 * 60 * 1000) {
                data.status = 'expired';
                return res.json({
                    success: true,
                    data: {
                        status: 'expired'
                    }
                });
            }
        }

        res.json({
            success: true,
            data: {
                status: data.status,
                userId: data.userId,
                userInfo: data.userInfo
            }
        });
    } catch (e) {
        console.error('???????????????', e);
        res.status(500).json({ success: false, message: '????????????? ' + e.message });
    }
});

// ????????????????????????????????????????????app.post('/api/auth/wechat/confirm', async (req, res) => {
    const { token, openid, nickname, avatar } = req.body;
    console.log('????????????????oken:', token);

    if (!token) {
        return res.status(400).json({ success: false, message: '???token???' });
    }

    try {
        const data = qrCodeTokens.get(token);

        if (!data) {
            return res.status(404).json({ success: false, message: '???????????????' });
        }

        if (data.status === 'expired') {
            return res.status(400).json({ success: false, message: '?????????' });
        }

        // ???????????        let userId;
        const openidToUse = openid || 'wechat_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);

        // ????????????????        try {
            const [cols] = await pool.execute('SHOW COLUMNS FROM users');
            const hasOpenid = cols.some(x => x.Field === 'openid');
            const hasWechatOpenid = cols.some(x => x.Field === 'wechat_openid');

            let userQuery = 'SELECT id FROM users WHERE ';
            if (hasOpenid) {
                userQuery += 'openid = ?';
            } else if (hasWechatOpenid) {
                userQuery += 'wechat_openid = ?';
            } else {
                // ??????openid????????hone?????????????????                userQuery = 'SELECT id FROM users WHERE phone = ? OR nickname = ?';
                const [users] = await pool.execute(userQuery, [openidToUse, nickname || '??????']);
                if (users.length > 0) {
                    userId = users[0].id;
                }
            }

            if (!userId) {
                if (hasOpenid || hasWechatOpenid) {
                    const [users] = await pool.execute(userQuery, [openidToUse]);
                    if (users.length > 0) {
                        userId = users[0].id;
                    }
                }
            }

            // ????????????????????            if (!userId) {
                const insertFields = ['role', 'login_method', 'created_at'];
                const insertValues = ['order_user', 'wechat', new Date()];

                if (hasOpenid) {
                    insertFields.push('openid');
                    insertValues.push(openidToUse);
                } else if (hasWechatOpenid) {
                    insertFields.push('wechat_openid');
                    insertValues.push(openidToUse);
                }

                // ???????????????????????                const hasNickname = cols.some(x => x.Field === 'nickname');
                const hasAvatar = cols.some(x => x.Field === 'avatar' || x.Field === 'avatar_url');

                if (hasNickname && nickname) {
                    insertFields.push('nickname');
                    insertValues.push(nickname);
                }
                if (hasAvatar && avatar) {
                    const avatarField = cols.find(x => x.Field === 'avatar' || x.Field === 'avatar_url')?.Field;
                    if (avatarField) {
                        insertFields.push(avatarField);
                        insertValues.push(avatar);
                    }
                }

                const placeholders = insertFields.map(() => '?').join(', ');
                const [result] = await pool.execute(
                    `INSERT INTO users (${insertFields.join(', ')}) VALUES (${placeholders})`,
                    insertValues
                );
                userId = result.insertId;
                console.log('??????????????ID:', userId);
            } else {
                console.log('????????????????D:', userId);
            }

            // ???token????            data.status = 'confirmed';
            data.userId = userId;
            data.userInfo = {
                nickname: nickname || '??????',
                avatar: avatar || '',
                openid: openidToUse
            };

            res.json({
                success: true,
                message: '?????????',
                data: {
                    userId: userId,
                    userInfo: data.userInfo
                }
            });
        } catch (dbError) {
            console.error('?????????????', dbError);
            throw dbError;
        }
    } catch (e) {
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    }
});

// ========== ????????? ==========

// ?????????
app.get('/api/payments/balance/:userId', async (req, res) => {
    const { userId } = req.params;
    console.log('?? ??????????????D:', userId);

    try {
        // ?????????????????????????????????
        const [rows] = await pool.execute('SELECT balance FROM users WHERE id = ?', [userId]);
        const balance = rows.length > 0 ? Number(rows[0].balance || 0) : 0;

        res.json({
            success: true,
            data: {
                balance: balance,
                available: balance
            }
        });
    } catch (e) {
        // ???????????????????        res.json({
            success: true,
            data: {
                balance: 0.00,
                available: 0.00
            }
        });
    }
});

// ?????????
app.post('/api/payments/create', async (req, res) => {
    const { order_id, user_id, amount, payment_method, discount = 0, openid } = req.body;
    console.log('?? ?????????:', { order_id, user_id, amount, payment_method });

    try {
        // ????????????????????
        const [orderCols] = await pool.execute('SHOW COLUMNS FROM orders');
        const has = (c) => orderCols.some(x => x.Field === c);
        const userCol = has('order_user_id') ? 'order_user_id' : (has('order_user') ? 'order_user' : (has('user_id') ? 'user_id' : null));

        if (!userCol) {
            return res.status(500).json({ success: false, message: '???????????????' });
        }

        // ??????????????????"?????"
        const [orderRows] = await pool.execute(`SELECT status, pickup_code FROM orders WHERE id = ? AND ${userCol} = ?`, [order_id, user_id]);
        if (orderRows.length === 0) {
            return res.status(404).json({ success: false, message: '???????? });
        }

        const orderStatus = Number(orderRows[0].status);
        if (orderStatus !== 7) { // 7 = ?????
            return res.status(400).json({ success: false, message: '?????????????????????"??????????? });
        }

        // ????????????
        if (payment_method === 'balance') {
            // ?????? - ??????
            const [userRows] = await pool.execute('SELECT balance FROM users WHERE id = ?', [user_id]);
            const balance = userRows.length > 0 ? Number(userRows[0].balance || 0) : 0;
            if (balance < amount) {
                return res.status(400).json({ success: false, message: '?????????' });
            }

            // ??????
            try {
                await pool.execute('UPDATE users SET balance = balance - ? WHERE id = ?', [amount, user_id]);
            } catch (e) {
                console.warn('????????????????????????:', e.message);
            }

            // ?????????
            try {
                const [payCols] = await pool.execute('SHOW COLUMNS FROM payments');
                const hasCol = (c) => payCols.some(x => x.Field === c);

                const payFields = [];
                const payValues = [];

                if (hasCol('order_id')) { payFields.push('order_id'); payValues.push(order_id); }
                if (hasCol('user_id')) { payFields.push('user_id'); payValues.push(user_id); }
                if (hasCol('amount')) { payFields.push('amount'); payValues.push(amount); }
                if (hasCol('payment_method')) { payFields.push('payment_method'); payValues.push(payment_method); }
                if (hasCol('discount')) { payFields.push('discount'); payValues.push(discount); }
                if (hasCol('status')) { payFields.push('status'); payValues.push('completed'); }
                if (hasCol('created_at')) { payFields.push('created_at'); payValues.push(new Date()); }

                if (payFields.length > 0) {
                    const placeholders = payFields.map(() => '?').join(', ');
                    await pool.execute(`INSERT INTO payments (${payFields.join(', ')}) VALUES (${placeholders})`, payValues);
                }
            } catch (e) {
                console.warn('????????????????????????:', e.message);
            }

            // ???????????"?????????            await pool.execute('UPDATE orders SET status = ?, updated_at = NOW() WHERE id = ?', [3, order_id]);

            // ?????????
            try {
                await pool.execute(
                    `INSERT INTO admin_operation_logs (admin_id, operation_type, target_type, target_id, operation_details, ip_address, user_agent)
                     VALUES (?, ?, 'order', ?, ?, ?, ?)`,
                    [0, 'payment', order_id, JSON.stringify({ user_id, amount, payment_method, discount }), req.ip, req.headers['user-agent']]
                );
            } catch (e) {
                console.warn('????????????(?????:', e.message);
            }

            return res.json({
                success: true,
                message: '??????',
                data: {
                    order_id,
                    amount,
                    payment_method,
                    status: 'completed'
                }
            });
        } else if (payment_method === 'wechat') {
            // ?????? - ?????????
            const orderInfo = orderRows[0];
            const description = `???????????????${orderInfo.pickup_code || order_id}`;

            const paymentResult = await paymentUtils.createWechatPayment({
                orderId: order_id,
                description: description,
                amount: amount,
                openid: openid, // ???????????????????penid
                clientIp: req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress
            });

            // ?????????????????????????????            try {
                const [payCols] = await pool.execute('SHOW COLUMNS FROM payments');
                const hasCol = (c) => payCols.some(x => x.Field === c);

                const payFields = ['status'];
                const payValues = ['pending']; // ?????
                if (hasCol('order_id')) { payFields.push('order_id'); payValues.push(order_id); }
                if (hasCol('user_id')) { payFields.push('user_id'); payValues.push(user_id); }
                if (hasCol('amount')) { payFields.push('amount'); payValues.push(amount); }
                if (hasCol('payment_method')) { payFields.push('payment_method'); payValues.push('wechat'); }
                if (hasCol('out_trade_no') || hasCol('outTradeNo')) {
                    const outTradeNoField = hasCol('out_trade_no') ? 'out_trade_no' : 'outTradeNo';
                    payFields.push(outTradeNoField);
                    payValues.push(paymentResult.outTradeNo);
                }
                if (hasCol('created_at')) { payFields.push('created_at'); payValues.push(new Date()); }

                if (payFields.length > 0) {
                    const placeholders = payFields.map(() => '?').join(', ');
                    await pool.execute(`INSERT INTO payments (${payFields.join(', ')}) VALUES (${placeholders})`, payValues);
                }
            } catch (e) {
                console.warn('????????????????????????:', e.message);
            }

            return res.json({
                success: true,
                message: '???????????????',
                data: {
                    paymentType: paymentResult.paymentType,
                    params: paymentResult.params, // JSAPI??????
                    paymentUrl: paymentResult.paymentUrl, // H5???URL
                    outTradeNo: paymentResult.outTradeNo
                }
            });
        } else if (payment_method === 'alipay') {
            // ????????- ?????????
            const orderInfo = orderRows[0];
            const description = `???????????????${orderInfo.pickup_code || order_id}`;

            const paymentResult = await paymentUtils.createAlipayPayment({
                orderId: order_id,
                description: description,
                amount: amount
            });

            // ?????????????????            try {
                const [payCols] = await pool.execute('SHOW COLUMNS FROM payments');
                const hasCol = (c) => payCols.some(x => x.Field === c);

                const payFields = ['status'];
                const payValues = ['pending'];

                if (hasCol('order_id')) { payFields.push('order_id'); payValues.push(order_id); }
                if (hasCol('user_id')) { payFields.push('user_id'); payValues.push(user_id); }
                if (hasCol('amount')) { payFields.push('amount'); payValues.push(amount); }
                if (hasCol('payment_method')) { payFields.push('payment_method'); payValues.push('alipay'); }
                if (hasCol('out_trade_no') || hasCol('outTradeNo')) {
                    const outTradeNoField = hasCol('out_trade_no') ? 'out_trade_no' : 'outTradeNo';
                    payFields.push(outTradeNoField);
                    payValues.push(paymentResult.outTradeNo);
                }
                if (hasCol('created_at')) { payFields.push('created_at'); payValues.push(new Date()); }

                if (payFields.length > 0) {
                    const placeholders = payFields.map(() => '?').join(', ');
                    await pool.execute(`INSERT INTO payments (${payFields.join(', ')}) VALUES (${placeholders})`, payValues);
                }
            } catch (e) {
                console.warn('????????????????????????:', e.message);
            }

            return res.json({
                success: true,
                message: '?????????????????,
                data: {
                    paymentType: paymentResult.paymentType,
                    paymentUrl: paymentResult.paymentUrl,
                    formHtml: paymentResult.formHtml, // ?????C???
                    outTradeNo: paymentResult.outTradeNo
                }
            });
        } else {
            return res.status(400).json({ success: false, message: '????????????' });
        }
    } catch (e) {
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '??????: ' + e.message });
    }
});

// ========== ????????? ==========

// ???????????????????????????????????app.post('/api/payments/wechat/notify', async (req, res) => {
    console.log('?? ????????????');

    try {
        // ???XML???
        const xmlData = req.body;
        let notifyData;

        if (typeof xmlData === 'string') {
            notifyData = paymentUtils.xmlToParams(xmlData);
        } else {
            notifyData = xmlData;
        }

        console.log('?? ????????????:', notifyData);

        // ??????
        const isValid = paymentUtils.verifyWechatSign(notifyData, paymentUtils.WECHAT_PAY_CONFIG.apiKey);
        if (!isValid) {
            console.error('????????????????????');
            return res.send(`<xml>
                <return_code><![CDATA[FAIL]]></return_code>
                <return_msg><![CDATA[?????????]]></return_msg>
            </xml>`);
        }

        // ?????????
        if (notifyData.result_code === 'SUCCESS' && notifyData.return_code === 'SUCCESS') {
            const outTradeNo = notifyData.out_trade_no;

            // ?????????
            const [payCols] = await pool.execute('SHOW COLUMNS FROM payments');
            const hasCol = (c) => payCols.some(x => x.Field === c);
            const outTradeNoField = hasCol('out_trade_no') ? 'out_trade_no' : (hasCol('outTradeNo') ? 'outTradeNo' : null);

            if (outTradeNoField) {
                const [payRows] = await pool.execute(`SELECT * FROM payments WHERE ${outTradeNoField} = ?`, [outTradeNo]);

                if (payRows.length > 0) {
                    const payment = payRows[0];

                    // ??????????                    await pool.execute('UPDATE payments SET payment_status = ? WHERE id = ?', [1, payment.id]);

                    // ???????????"?????????                    const orderIdField = hasCol('order_id') ? 'order_id' : null;
                    if (orderIdField && payment[orderIdField]) {
                        await pool.execute('UPDATE orders SET status = ?, updated_at = NOW() WHERE id = ?', [3, payment[orderIdField]]);
                    }

                    console.log('????????????????D:', payment[orderIdField]);
                }
            }

            // ??????????????            return res.send(`<xml>
                <return_code><![CDATA[SUCCESS]]></return_code>
                <return_msg><![CDATA[OK]]></return_msg>
            </xml>`);
        } else {
            console.warn('??? ??????????????????:', notifyData.err_code_des || notifyData.return_msg);
            return res.send(`<xml>
                <return_code><![CDATA[FAIL]]></return_code>
                <return_msg><![CDATA[??????]]></return_msg>
            </xml>`);
        }
    } catch (e) {
        console.error('?????????????????:', e);
        return res.send(`<xml>
            <return_code><![CDATA[FAIL]]></return_code>
            <return_msg><![CDATA[??????]]></return_msg>
        </xml>`);
    }
});

// ???????????app.post('/api/payments/alipay/notify', async (req, res) => {
    console.log('?? ??????????????);

    try {
        const notifyData = req.body;
        console.log('?? ??????????????', notifyData);

        // ??????
        const isValid = paymentUtils.verifyAlipaySign(notifyData, paymentUtils.ALIPAY_CONFIG.alipayPublicKey);
        if (!isValid) {
            console.error('??????????????????????);
            return res.send('fail');
        }

        // ?????????
        if (notifyData.trade_status === 'TRADE_SUCCESS' || notifyData.trade_status === 'TRADE_FINISHED') {
            const outTradeNo = notifyData.out_trade_no;

            // ?????????
            const [payCols] = await pool.execute('SHOW COLUMNS FROM payments');
            const hasCol = (c) => payCols.some(x => x.Field === c);
            const outTradeNoField = hasCol('out_trade_no') ? 'out_trade_no' : (hasCol('outTradeNo') ? 'outTradeNo' : null);

            if (outTradeNoField) {
                const [payRows] = await pool.execute(`SELECT * FROM payments WHERE ${outTradeNoField} = ?`, [outTradeNo]);

                if (payRows.length > 0) {
                    const payment = payRows[0];

                    // ?????????
                    if (payment.status !== 'completed') {
                        // ??????????                        await pool.execute('UPDATE payments SET payment_status = ? WHERE id = ?', [1, payment.id]);

                        // ???????????"?????????                        const orderIdField = hasCol('order_id') ? 'order_id' : null;
                        if (orderIdField && payment[orderIdField]) {
                            await pool.execute('UPDATE orders SET status = ?, updated_at = NOW() WHERE id = ?', [3, payment[orderIdField]]);
                        }

                        console.log('?????????????????ID:', payment[orderIdField]);
                    }
                }
            }

            // ???????????????
            return res.send('success');
        } else {
            console.warn('??? ????????????????????', notifyData.trade_status);
            return res.send('fail');
        }
    } catch (e) {
        console.error('???????????????????', e);
        return res.send('fail');
    }
});

// ??????
app.get('/api/auth/test', (req, res) => {
    console.log('??/api/auth/test ?????);
    res.json({
        success: true,
        message: '????????????',
        timestamp: new Date().toISOString()
    });
});

app.post('/api/auth/test-post', (req, res) => {
    console.log('??/api/auth/test-post ?????, req.body);
    res.json({
        success: true,
        message: 'POST????????????',
        receivedBody: req.body
    });
});
// ========== ????????? ==========

// ?????????
app.get('/api/courier-users/performance/:userId', (req, res) => {
    const { userId } = req.params;
    const { timeRange, startDate, endDate, comparePeriod } = req.query;

    console.log('?? ??????????????D:', userId, '??????:', timeRange);

    res.json({
        success: true,
        data: {
            completedOrders: 25,
            totalIncome: 125.50,
            avgRating: 4.8,
            responseTime: 15.2,
            completionRate: 96,
            comparedToLastPeriod: {
                completedOrders: 5,
                totalIncome: 25.50,
                avgRating: 0.2,
                responseTime: -2.1,
                completionRate: 2
            }
        }
    });
});

// ????????????
app.get('/api/courier-users/performance/chart', (req, res) => {
    const { userId, timeRange, startDate, endDate } = req.query;

    console.log('?? ?????????????????D:', userId, '??????:', timeRange);

    res.json({
        success: true,
        data: [
            { date: '10-12', orders: 4, income: 20.00 },
            { date: '10-13', orders: 5, income: 25.00 },
            { date: '10-14', orders: 3, income: 15.00 },
            { date: '10-15', orders: 6, income: 30.00 },
            { date: '10-16', orders: 4, income: 20.00 },
            { date: '10-17', orders: 2, income: 10.00 },
            { date: '10-18', orders: 1, income: 5.50 }
        ]
    });
});

// ?????????
app.get('/api/courier-users/performance/ratings', (req, res) => {
    const { userId, timeRange } = req.query;

    console.log('????????????????D:', userId);

    res.json({
        success: true,
        data: {
            distribution: [
                { rating: 5, count: 20, percentage: 80 },
                { rating: 4, count: 4, percentage: 16 },
                { rating: 3, count: 1, percentage: 4 },
                { rating: 2, count: 0, percentage: 0 },
                { rating: 1, count: 0, percentage: 0 }
            ],
            averageRating: 4.8,
            totalRatings: 25
        }
    });
});

// ?????????
app.get('/api/courier-users/performance/ranking', (req, res) => {
    const { userId, timeRange } = req.query;

    console.log('?? ??????????????D:', userId);

    res.json({
        success: true,
        data: {
            currentRank: 12,
            totalCouriers: 156,
            topPercentage: 8,
            improvement: 3,
            metrics: {
                completedOrders: { rank: 15, total: 156 },
                avgRating: { rank: 8, total: 156 },
                responseTime: { rank: 20, total: 156 },
                completionRate: { rank: 10, total: 156 }
            }
        }
    });
});
// ========== ???????????==========

// ???????????app.get('/api/couriers/:courierId', async (req, res) => {
    const { courierId } = req.params;
    console.log('?? ?????????????????D:', courierId);

    try {
        const [users] = await pool.execute(
            `SELECT u.id, u.phone, u.nickname, u.role, u.created_at, u.account_status,
                    cu.*
             FROM users u
             LEFT JOIN courier_users cu ON cu.user_id = u.id
             WHERE u.id = ?`,
            [courierId]
        );

        if (users.length === 0) {
            return res.json({
                success: false,
                message: '?????????'
            });
        }

        const user = users[0];
        res.json({ success: true, data: users[0] });
    } catch (error) {
        console.error('????????????????', error);
        res.json({
            success: false,
            message: '??????????????
        });
    }
});

// ???????????app.get('/api/couriers/credit/:courierId', async (req, res) => {
    const { courierId } = req.params;
    console.log('?? ?????????????????D:', courierId);

    res.json({
        success: true,
        data: {
            credit: 100,
            level: '???'
        }
    });
});

// ???????????app.get('/api/couriers/income/:courierId', async (req, res) => {
    const { courierId } = req.params;
    console.log('?? ?????????????????D:', courierId);

    res.json({
        success: true,
        data: {
            total: 0.00,
            today: 0.00,
            month: 0.00
        }
    });
});

// ???????????app.get('/api/couriers/performance/:courierId', async (req, res) => {
    const { courierId } = req.params;
    console.log('?? ?????????????????D:', courierId);

    res.json({
        success: true,
        data: {
            completedOrders: 0,
            responseTime: 0,
            rating: 0.0
        }
    });
});

// ??? ??????/api/orders/available ?????? orderRoutes.js ?????// ????????????????????

// ??????????????app.get('/api/courier-users/income/:userId', (req, res) => {
    console.log('?? ??????????????????????????D:', req.params.userId);
    res.json({
        success: true,
        data: {
            total: 1250.00,
            today: 85.00,
            month: 1250.00,
            available: 0
        }
    });
});

// ????????????
app.get('/api/incomes', (req, res) => {
    console.log('?? ?????????????????);
    res.json({
        success: true,
        data: {
            list: [],
            total: 0,
            page: 1,
            pageSize: 10,
            hasMore: false
        }
    });
});

// ????????????
app.get('/api/incomes/chart', (req, res) => {
    console.log('?? ?????????????????);
    res.json({
        success: true,
        data: [
            { date: '10-12', amount: 45 },
            { date: '10-13', amount: 52 },
            { date: '10-14', amount: 38 },
            { date: '10-15', amount: 65 },
            { date: '10-16', amount: 72 },
            { date: '10-17', amount: 58 },
            { date: '10-18', amount: 85 }
        ]
    });
});

// ========== ?????? CRUD?????? addresses??==========
// GET ???
app.get('/api/addresses/:userId', async (req, res) => {
    const { userId } = req.params;
    try {
        const [rows] = await pool.execute(
            `SELECT id, user_id, name, phone, full_address, is_default, created_at, updated_at
             FROM addresses WHERE user_id = ?
             ORDER BY is_default DESC, id DESC`,
            [userId]
        );
        res.json({ success: true, data: rows });
    } catch (e) {
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    }
});

// POST ???
app.post('/api/addresses', async (req, res) => {
    const { user_id, name, phone, full_address, is_default } = req.body || {};
    if (!user_id || !name || !phone || !full_address) return res.json({ success: false, message: '?????????' });
    const conn = await pool.getConnection();
    try {
        await conn.beginTransaction();
        if (is_default) {
            await conn.execute('UPDATE addresses SET is_default = 0 WHERE user_id = ?', [user_id]);
        }
        const [ret] = await conn.execute(
            `INSERT INTO addresses (user_id, name, phone, full_address, is_default, created_at, updated_at)
             VALUES (?, ?, ?, ?, ?, NOW(), NOW())`,
            [user_id, name, phone, full_address, is_default ? 1 : 0]
        );
        await conn.commit();
        res.json({ success: true, id: ret.insertId });
    } catch (e) {
        await conn.rollback();
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    } finally {
        conn.release();
    }
});

// PUT ???
app.put('/api/addresses/:id', async (req, res) => {
    const { id } = req.params;
    const { user_id, name, phone, full_address, is_default } = req.body || {};
    if (!user_id || !name || !phone || !full_address) return res.json({ success: false, message: '?????????' });
    const conn = await pool.getConnection();
    try {
        await conn.beginTransaction();
        if (is_default) {
            await conn.execute('UPDATE addresses SET is_default = 0 WHERE user_id = ?', [user_id]);
        }
        await conn.execute(
            `UPDATE addresses SET name=?, phone=?, full_address=?, is_default=?, updated_at=NOW() WHERE id=? AND user_id=?`,
            [name, phone, full_address, is_default ? 1 : 0, id, user_id]
        );
        await conn.commit();
        res.json({ success: true });
    } catch (e) {
        await conn.rollback();
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    } finally {
        conn.release();
    }
});

// DELETE ???
app.delete('/api/addresses/:id', async (req, res) => {
    const { id } = req.params;
    try {
        await pool.execute('DELETE FROM addresses WHERE id=?', [id]);
        res.json({ success: true });
    } catch (e) {
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    }
});

// ??????
app.put('/api/addresses/:id/default', async (req, res) => {
    const { id } = req.params;
    const { user_id } = req.body || {};
    if (!user_id) return res.json({ success: false, message: '??? user_id' });
    const conn = await pool.getConnection();
    try {
        await conn.beginTransaction();
        await conn.execute('UPDATE addresses SET is_default = 0 WHERE user_id = ?', [user_id]);
        await conn.execute('UPDATE addresses SET is_default = 1, updated_at=NOW() WHERE id = ? AND user_id = ?', [id, user_id]);
        await conn.commit();
        res.json({ success: true });
    } catch (e) {
        await conn.rollback();
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    } finally {
        conn.release();
    }
});

// ????????????????app.post('/api/couriers/toggle-accepting', (req, res) => {
    console.log('?? ????????????????????', req.body);
    res.json({
        success: true,
        message: req.body.isAccepting ? '??????? : '??????',
        data: {
            isAccepting: req.body.isAccepting
        }
    });
});

// =========================
// ???/??? ???
// =========================

// ???????????????????????
app.post('/api/messages/conversations', async (req, res) => {
    const { participants, order_id, type } = req.body || {};
    if (!Array.isArray(participants) || participants.length < 2) {
        return res.json({ success: false, message: 'participants ???????2 ?????D' });
    }
    // ????????????
    const participantsUnique = Array.from(new Set(participants.map(n => Number(n)))).filter(Boolean);
    if (participantsUnique.length < 2) {
        return res.json({ success: false, message: '??????????? });
    }
    const convType = Number(type) || 1;
    const conn = await pool.getConnection();
    try {
        await conn.beginTransaction();
        // ?????????????????????????????????
        let conversationId = null;
        if (participantsUnique.length === 2) {
            const [exist] = await conn.execute(
                `SELECT c.id
                 FROM conversations c
                 JOIN conversation_participants p1 ON p1.conversation_id=c.id AND p1.user_id=?
                 JOIN conversation_participants p2 ON p2.conversation_id=c.id AND p2.user_id=?
                 WHERE c.type=? AND ${order_id ? 'c.order_id = ?' : 'c.order_id IS NULL'}
                 ORDER BY c.updated_at DESC, c.id DESC
                 LIMIT 1`,
                order_id ? [participantsUnique[0], participantsUnique[1], convType, order_id] : [participantsUnique[0], participantsUnique[1], convType]
            );
            if (exist && exist.length) conversationId = exist[0].id;
        }

        if (!conversationId) {
            const [ins] = await conn.execute(
                'INSERT INTO conversations (order_id, type) VALUES (?, ?)',
                [order_id || null, convType]
            );
            conversationId = ins.insertId;
        }

        for (const uid of participantsUnique) {
            await conn.execute(
                'INSERT IGNORE INTO conversation_participants (conversation_id, user_id, role) VALUES (?, ?, NULL)',
                [conversationId, uid]
            );
        }
        await conn.commit();
        res.json({ success: true, data: { id: conversationId } });
    } catch (e) {
        await conn.rollback();
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    } finally {
        conn.release();
    }
});

// ????????????????????????????????
app.get('/api/messages/conversations', async (req, res) => {
    const userId = Number(req.query.userId);
    if (!userId) return res.json({ success: false, message: '??? userId' });
    try {
        // ????orders ?????? pickup_code ??        const [cols] = await pool.execute('SHOW COLUMNS FROM orders LIKE "pickup_code"');
        const hasPickupCode = cols.length > 0;

        const pickupCodeSelect = hasPickupCode ? 'o.pickup_code' : 'NULL AS pickup_code';

        const [rows] = await pool.execute(`
            SELECT 
              c.id, c.order_id, c.type, c.updated_at,
              ${pickupCodeSelect},
              (
                SELECT JSON_OBJECT(
                  'id', m.id,
                  'sender_id', m.sender_id,
                  'content', m.content,
                  'content_type', m.content_type,
                  'created_at', m.created_at
                )
                FROM messages m
                WHERE m.conversation_id = c.id
                ORDER BY m.created_at DESC, m.id DESC
                LIMIT 1
              ) AS last_message,
              (
                SELECT COUNT(1)
                FROM messages m
                WHERE m.conversation_id = c.id
                  AND m.sender_id <> ?
                  AND NOT EXISTS (
                    SELECT 1 FROM message_reads r
                    WHERE r.message_id = m.id AND r.user_id = ?
                  )
              ) AS unread_count
            FROM conversations c
            JOIN conversation_participants cp ON cp.conversation_id = c.id
            ${hasPickupCode ? 'LEFT JOIN orders o ON o.id = c.order_id' : ''}
            WHERE cp.user_id = ?
            ORDER BY c.updated_at DESC
        `, [userId, userId, userId]);
        res.json({ success: true, data: rows });
    } catch (e) {
        console.error('??????????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    }
});

// ?????????????????// ????????????????????????????????:conversationId ?????app.get('/api/messages/unread-count', async (req, res) => {
    const userId = Number(req.query.userId);
    if (!userId) return res.json({ success: false, message: '??? userId' });

    try {
        // ??????????????
        const [messagesTable] = await pool.execute("SHOW TABLES LIKE 'messages'").catch(() => [[]]);

        if (messagesTable.length === 0) {
            // ???????????
            return res.json({ success: true, data: { unread: 0 } });
        }

        const [rows] = await pool.execute(`
            SELECT COUNT(1) AS cnt
            FROM messages m
            LEFT JOIN conversation_participants cp ON cp.conversation_id = m.conversation_id AND cp.user_id = ?
            WHERE m.sender_id <> ?
                AND NOT EXISTS (
                    SELECT 1 FROM message_reads r WHERE r.message_id = m.id AND r.user_id = ?
                )
        `, [userId, userId, userId]).catch(() => [[{ cnt: 0 }]]);

        res.json({ success: true, data: { unread: (rows[0] && rows[0].cnt) || 0 } });
    } catch (e) {
        console.error('?????????????', e);
        // ??????????????????????        res.json({ success: true, data: { unread: 0 } });
    }
});

app.get('/api/messages/:conversationId', async (req, res) => {
    const { conversationId } = req.params;
    const page = Number(req.query.page) || 1;
    const size = Number(req.query.size) || 20;
    const sizeInt = Math.max(1, Math.min(100, Number(size)));
    const offsetInt = Math.max(0, (Number(page) - 1) * sizeInt);
    try {
        const sql = `SELECT id, sender_id, content, content_type, status, created_at
                     FROM messages
                     WHERE conversation_id = ?
                     ORDER BY created_at ASC, id ASC
                     LIMIT ${sizeInt} OFFSET ${offsetInt}`;
        const [rows] = await pool.execute(sql, [conversationId]);
        res.json({ success: true, data: rows });
    } catch (e) {
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    }
});

// ???????app.post('/api/messages/:conversationId/send', async (req, res) => {
    const { conversationId } = req.params;
    const { sender_id, content, content_type } = req.body || {};
    if (!sender_id || !content) return res.json({ success: false, message: '??? sender_id ??content' });
    try {
        // ????????????
        const [p] = await pool.execute(
            'SELECT 1 FROM conversation_participants WHERE conversation_id = ? AND user_id = ? LIMIT 1',
            [conversationId, sender_id]
        );
        if (p.length === 0) return res.status(403).json({ success: false, message: '???????? });

        const [ins] = await pool.execute(
            'INSERT INTO messages (conversation_id, sender_id, content, content_type, status) VALUES (?, ?, ?, ?, 0)',
            [conversationId, sender_id, content, content_type || 'text']
        );
        await pool.execute('UPDATE conversations SET updated_at = NOW() WHERE id = ?', [conversationId]);
        res.json({ success: true, data: { id: ins.insertId } });
    } catch (e) {
        console.error('????????????', e);
        res.status(500).json({ success: false, message: '?????????? ' + e.message });
    }
});

// ????????? <= last_message_id ??????????????app.post('/api/messages/:conversationId/read', async (req, res) => {
    const { conversationId } = req.params;
    const { user_id, last_message_id } = req.body || {};
    if (!user_id || !last_message_id) return res.json({ success: false, message: '??? user_id ??last_message_id' });
    try {
        await pool.execute(
            `INSERT IGNORE INTO message_reads (message_id, user_id, read_at)
             SELECT id, ?, NOW() FROM messages
             WHERE conversation_id = ? AND id <= ?`,
            [user_id, conversationId, last_message_id]
        );
        res.json({ success: true });
    } catch (e) {
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    }
});

// ??????
// ?????????????????????????????????????
// ??????????????
app.post('/api/admin/broadcasts', async (req, res) => {
    const { admin_id, title, content, target_role, expires_at } = req.body || {};
    if (!admin_id || !title || !content) return res.json({ success: false, message: '?????????' });
    try {
        const [ins] = await pool.execute(
            'INSERT INTO admin_broadcasts (admin_id, title, content, target_role, expires_at, status) VALUES (?, ?, ?, ?, ?, 1)',
            [admin_id, title, content, target_role || null, expires_at || null]
        );
        res.json({ success: true, data: { id: ins.insertId } });
    } catch (e) {
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    }
});

app.get('/api/admin/broadcasts', async (req, res) => {
    const role = req.query.role || null; // orderer/courier/admin/all
    try {
        const params = [];
        let where = 'WHERE status = 1 AND (expires_at IS NULL OR expires_at > NOW())';
        if (role && role !== 'all') {
            where += ' AND (target_role = ? OR target_role = "all")';
            params.push(role);
        }
        const [rows] = await pool.execute(
            `SELECT id, admin_id, title, content, target_role, created_at, expires_at FROM admin_broadcasts ${where} ORDER BY id DESC`,
            params
        );
        res.json({ success: true, data: rows });
    } catch (e) {
        console.error('???????????:', e);
        res.status(500).json({ success: false, message: '?????????: ' + e.message });
    }
});

// ??????
app.get('/api/hello', (req, res) => {
    console.log('??/api/hello ?????);
    res.json({
        message: 'Hello from Campus Express API!',
        timestamp: new Date().toISOString()
    });
});

// ??????????app.get('/api/health', (req, res) => {
    console.log('??/api/health ?????);
    res.json({
        status: 'OK',
        service: 'Campus Express API',
        timestamp: new Date().toISOString(),
        version: '1.0.0'
    });
});

// ========== ??????????????????????????? ==========

const passwordHelper = require('./utils/passwordHelper');

// ???????????????????????
app.get('/api/debug/password/:phone', async (req, res) => {
    const { phone } = req.params;
    console.log('?? ??????????????????:', phone);

    try {
        const result = await passwordHelper.getUserPasswordHash(phone);

        if (!result.found) {
            return res.json({
                success: false,
                message: result.message
            });
        }

        res.json({
            success: true,
            data: {
                userId: result.userId,
                phone: result.phone,
                nickname: result.nickname,
                role: result.role,
                hasPassword: result.hasPassword,
                passwordHash: result.passwordHash ? `${result.passwordHash.substring(0, 20)}...` : null
            },
            message: result.hasPassword
                ? '????????????????????????'
                : '???????????
        });
    } catch (error) {
        console.error('????????:', error);
        res.status(500).json({
            success: false,
            message: '??????: ' + error.message
        });
    }
});

// ?????????????????app.post('/api/debug/reset-password', async (req, res) => {
    const { phone, newPassword } = req.body;
    console.log('?? ???????????????:', phone);

    if (!phone || !newPassword) {
        return res.status(400).json({
            success: false,
            message: '???????????????'
        });
    }

    try {
        const result = await passwordHelper.resetUserPassword(phone, newPassword);

        if (!result.success) {
            return res.json({
                success: false,
                message: result.message
            });
        }

        res.json({
            success: true,
            message: '?????????',
            data: {
                userId: result.userId,
                phone: result.phone,
                newPassword: newPassword // ???????????            }
        });
    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({
            success: false,
            message: '?????????: ' + error.message
        });
    }
});

// ???????????????????????
// ============================================
// ?????????API
// ============================================

// ????????????
app.get('/api/users/:userId/notification-settings', async (req, res) => {
    const { userId } = req.params;
    console.log('?? ??????????????D:', userId);

    try {
        const [settings] = await pool.execute(
            `SELECT * FROM user_notification_settings WHERE user_id = ?`,
            [userId]
        );

        if (settings.length === 0) {
            // ???????????????????            return res.json({
                success: true,
                data: {
                    notifications_enabled: true,
                    order_status_change: true,
                    order_delivered: true,
                    payment_reminder: true,
                    account_security: true,
                    version_update: false,
                    promotions: false,
                    new_features: false,
                    notification_method: 'app'
                }
            });
        }

        res.json({
            success: true,
            data: settings[0]
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ????????????
app.put('/api/users/:userId/notification-settings', async (req, res) => {
    const { userId } = req.params;
    const {
        notifications_enabled,
        order_status_change,
        order_delivered,
        payment_reminder,
        account_security,
        version_update,
        promotions,
        new_features,
        notification_method
    } = req.body;

    console.log('?? ??????????????D:', userId);

    try {
        // ?????????????        const [users] = await pool.execute('SELECT id FROM users WHERE id = ?', [userId]);
        if (users.length === 0) {
            return res.status(404).json({ success: false, message: '???????? });
        }

        // ?????????????        const [existing] = await pool.execute(
            'SELECT id FROM user_notification_settings WHERE user_id = ?',
            [userId]
        );

        if (existing.length > 0) {
            // ?????????
            await pool.execute(
                `UPDATE user_notification_settings SET
                 notifications_enabled = ?,
                 order_status_change = ?,
                 order_delivered = ?,
                 payment_reminder = ?,
                 account_security = ?,
                 version_update = ?,
                 promotions = ?,
                 new_features = ?,
                 notification_method = ?,
                 updated_at = NOW()
                 WHERE user_id = ?`,
                [
                    notifications_enabled !== undefined ? notifications_enabled : 1,
                    order_status_change !== undefined ? order_status_change : 1,
                    order_delivered !== undefined ? order_delivered : 1,
                    payment_reminder !== undefined ? payment_reminder : 1,
                    account_security !== undefined ? account_security : 1,
                    version_update !== undefined ? version_update : 0,
                    promotions !== undefined ? promotions : 0,
                    new_features !== undefined ? new_features : 0,
                    notification_method || 'app',
                    userId
                ]
            );
        } else {
            // ????????            await pool.execute(
                `INSERT INTO user_notification_settings 
                (user_id, notifications_enabled, order_status_change, order_delivered, 
                 payment_reminder, account_security, version_update, promotions, 
                 new_features, notification_method)
                 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
                [
                    userId,
                    notifications_enabled !== undefined ? notifications_enabled : 1,
                    order_status_change !== undefined ? order_status_change : 1,
                    order_delivered !== undefined ? order_delivered : 1,
                    payment_reminder !== undefined ? payment_reminder : 1,
                    account_security !== undefined ? account_security : 1,
                    version_update !== undefined ? version_update : 0,
                    promotions !== undefined ? promotions : 0,
                    new_features !== undefined ? new_features : 0,
                    notification_method || 'app'
                ]
            );
        }

        res.json({
            success: true,
            message: '???????????
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '??????: ' + error.message });
    }
});

// ============================================
// ?????????API
// ============================================

// ????????????
app.get('/api/admin/finance/stats', async (req, res) => {
    try {
        // ?????????????????????????????- payment_status: 1=?????        const [monthlyRevenue] = await pool.execute(
            `SELECT COALESCE(SUM(p.amount), 0) AS total
             FROM payments p
             WHERE p.payment_status = 1
             AND MONTH(p.created_at) = MONTH(NOW())
             AND YEAR(p.created_at) = YEAR(NOW())`
        );

        // ???????????????????????
        const [lastMonthRevenue] = await pool.execute(
            `SELECT COALESCE(SUM(p.amount), 0) AS total
             FROM payments p
             WHERE p.payment_status = 1
             AND MONTH(p.created_at) = MONTH(DATE_SUB(NOW(), INTERVAL 1 MONTH))
             AND YEAR(p.created_at) = YEAR(DATE_SUB(NOW(), INTERVAL 1 MONTH))`
        );

        // ?????????????????????????????        const [pendingSettlement] = await pool.execute(
            `SELECT 
                COUNT(*) AS order_count,
                COALESCE(SUM(o.final_fee), 0) AS total_amount
             FROM orders o
             WHERE o.status IN (4, 7) 
             AND NOT EXISTS (SELECT 1 FROM payments p WHERE p.order_id = o.id AND p.payment_status = 1)`
        );

        // ?????????????????????????????        const [settled] = await pool.execute(
            `SELECT 
                COUNT(*) AS order_count,
                COALESCE(SUM(p.amount), 0) AS total_amount
             FROM payments p
             WHERE p.payment_status = 1
             AND MONTH(p.created_at) = MONTH(NOW())
             AND YEAR(p.created_at) = YEAR(NOW())`
        );

        // ???????????????????????        // ??????????????        const [profitRule] = await pool.execute(
            `SELECT commission_rate FROM profit_rules WHERE is_active = 1 AND rule_type = 'commission_rate' LIMIT 1`
        );
        const commissionRate = profitRule.length > 0 ? (profitRule[0].commission_rate || 10) : 10;
        const platformFee = (monthlyRevenue[0]?.total || 0) * (commissionRate / 100);

        // ????????        const lastMonthTotal = lastMonthRevenue[0]?.total || 0;
        const currentMonthTotal = monthlyRevenue[0]?.total || 0;
        const growthRate = lastMonthTotal > 0
            ? ((currentMonthTotal - lastMonthTotal) / lastMonthTotal * 100).toFixed(1)
            : 0;

        res.json({
            success: true,
            data: {
                monthlyRevenue: monthlyRevenue[0]?.total || 0,
                growthRate: parseFloat(growthRate),
                pendingSettlement: pendingSettlement[0]?.total_amount || 0,
                pendingOrderCount: pendingSettlement[0]?.order_count || 0,
                settled: settled[0]?.total_amount || 0,
                settledOrderCount: settled[0]?.order_count || 0,
                platformFee: platformFee,
                commissionRate: commissionRate
            }
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '?????????' });
    }
});

// ????????????
app.get('/api/admin/finance/transactions', async (req, res) => {
    const { page = 1, pageSize = 20, status = '', startDate = '', endDate = '' } = req.query || {};
    const offset = (Number(page) - 1) * Number(pageSize);

    try {
        const where = ['1=1'];
        const params = [];

        if (status) {
            // ????????'completed' -> 1, 'pending' -> 0, 'timeout' -> 2
            let statusValue = status;
            if (status === 'completed') statusValue = 1;
            else if (status === 'pending') statusValue = 0;
            else if (status === 'timeout') statusValue = 2;
            where.push('p.payment_status = ?');
            params.push(statusValue);
        }

        if (startDate) {
            where.push('DATE(p.created_at) >= ?');
            params.push(startDate);
        }

        if (endDate) {
            where.push('DATE(p.created_at) <= ?');
            params.push(endDate);
        }

        const whereSQL = where.join(' AND ');

        const [rows] = await pool.execute(
            `SELECT 
                p.id AS transaction_id,
                CONCAT('#TXN', LPAD(p.id, 8, '0')) AS transaction_no,
                p.order_id,
                CONCAT('#ORD', LPAD(p.order_id, 8, '0')) AS order_no,
                p.amount,
                p.payment_status AS status,
                p.created_at,
                u.nickname AS user_name,
                u.phone AS user_phone,
                '??????' AS transaction_type,
                CASE
                    WHEN EXISTS (SELECT 1 FROM orders o WHERE o.id = p.order_id AND o.courier_user_id IS NOT NULL) THEN '????????
                    ELSE '??????'
                END AS category,
                (p.amount * (SELECT COALESCE(commission_rate, 10) FROM profit_rules WHERE is_active = 1 AND rule_type = 'commission_rate' LIMIT 1) / 100) AS commission_fee
             FROM payments p
             LEFT JOIN orders o ON o.id = p.order_id
             LEFT JOIN order_users ou ON ou.id = o.order_user_id
             LEFT JOIN users u ON u.id = ou.user_id
             WHERE ${whereSQL}
             ORDER BY p.created_at DESC
             LIMIT ? OFFSET ?`,
            [...params, Number(pageSize), offset]
        );

        const [cnt] = await pool.execute(
            `SELECT COUNT(*) AS total FROM payments p WHERE ${whereSQL}`,
            params
        );

        res.json({
            success: true,
            data: rows,
            total: cnt[0]?.total || 0,
            page: Number(page),
            pageSize: Number(pageSize)
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ?????????????????????
app.get('/api/admin/finance/revenue-trend', async (req, res) => {
    const { days = 7 } = req.query || {};

    try {
        const [rows] = await pool.execute(
            `SELECT 
                DATE(p.created_at) AS date,
                SUM(CASE WHEN p.payment_status = 1 THEN p.amount ELSE 0 END) AS revenue,
                SUM(CASE WHEN EXISTS (SELECT 1 FROM orders o WHERE o.id = p.order_id AND o.courier_user_id IS NOT NULL) 
                          AND p.payment_status = 1 THEN p.amount ELSE 0 END) AS expense
             FROM payments p
             WHERE p.created_at >= DATE_SUB(NOW(), INTERVAL ? DAY)
             GROUP BY DATE(p.created_at)
             ORDER BY date ASC`,
            [Number(days)]
        );

        res.json({
            success: true,
            data: rows
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ============================================
// ?????????API
// ============================================

// ?????????
app.get('/api/admin/announcements', async (req, res) => {
    const { page = 1, pageSize = 20, status = '', type = '' } = req.query || {};
    const offset = (Number(page) - 1) * Number(pageSize);

    try {
        const where = ['1=1'];
        const params = [];

        if (status === 'published') {
            where.push('a.is_published = 1');
        } else if (status === 'draft') {
            where.push('a.is_published = 0');
        }

        if (type) {
            where.push('a.type = ?');
            params.push(type);
        }

        const whereSQL = where.join(' AND ');

        const [rows] = await pool.execute(
            `SELECT 
                a.*,
                u.nickname AS creator_name
             FROM announcements a
             LEFT JOIN users u ON u.id = a.created_by
             WHERE ${whereSQL}
             ORDER BY a.is_top DESC, a.published_at DESC, a.created_at DESC
             LIMIT ? OFFSET ?`,
            [...params, Number(pageSize), offset]
        );

        const [cnt] = await pool.execute(
            `SELECT COUNT(*) AS total FROM announcements a WHERE ${whereSQL}`,
            params
        );

        res.json({
            success: true,
            data: rows,
            total: cnt[0]?.total || 0
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ????????????????????????????????????
app.get('/api/announcements', async (req, res) => {
    const { limit = 10 } = req.query || {};

    try {
        // ???????????
        const [tableCheck] = await pool.execute(
            "SHOW TABLES LIKE 'announcements'"
        ).catch(() => [[]]);

        if (tableCheck.length === 0) {
            // ???????????????
            return res.json({
                success: true,
                data: []
            });
        }

        let rows = [];
        try {
            const [result] = await pool.execute(
                `SELECT id, title, content, type, is_top, created_at, published_at
                 FROM announcements
                 WHERE is_published = 1
                 ORDER BY is_top DESC, published_at DESC, created_at DESC
                 LIMIT ?`,
                [Number(limit)]
            );
            rows = result || [];
        } catch (queryError) {
            console.warn('??? ???????????', queryError.message);
            // ??????????????????????????            rows = [];
        }

        res.json({
            success: true,
            data: rows
        });

    } catch (error) {
        console.error('???????????:', error);
        // ??????????????????????????        res.json({
            success: true,
            data: []
        });
    }
});

// ??????
app.post('/api/admin/announcements', async (req, res) => {
    const { title, content, type = 'notice', is_top = 0, is_published = 0 } = req.body;
    const adminId = req.user?.userId || 0; // ??WT token????????D

    if (!title || !content) {
        return res.status(400).json({ success: false, message: '?????????????? });
    }

    try {
        const [result] = await pool.execute(
            `INSERT INTO announcements 
            (title, content, type, is_top, is_published, created_by, published_at)
            VALUES (?, ?, ?, ?, ?, ?, ?)`,
            [
                title,
                content,
                type,
                is_top ? 1 : 0,
                is_published ? 1 : 0,
                adminId || null,
                is_published ? new Date() : null
            ]
        );

        res.json({
            success: true,
            message: is_published ? '?????????' : '???????????,
            data: { id: result.insertId }
        });

    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ??????
app.put('/api/admin/announcements/:id', async (req, res) => {
    const { id } = req.params;
    const { title, content, type, is_top, is_published } = req.body;

    try {
        // ?????????????        const [existing] = await pool.execute(
            'SELECT id FROM announcements WHERE id = ?',
            [id]
        );

        if (existing.length === 0) {
            return res.status(404).json({ success: false, message: '???????? });
        }

        // ??????SQL
        const updates = [];
        const values = [];

        if (title !== undefined) {
            updates.push('title = ?');
            values.push(title);
        }
        if (content !== undefined) {
            updates.push('content = ?');
            values.push(content);
        }
        if (type !== undefined) {
            updates.push('type = ?');
            values.push(type);
        }
        if (is_top !== undefined) {
            updates.push('is_top = ?');
            values.push(is_top ? 1 : 0);
        }
        if (is_published !== undefined) {
            updates.push('is_published = ?');
            values.push(is_published ? 1 : 0);
            if (is_published && !existing[0].published_at) {
                updates.push('published_at = NOW()');
            }
        }
        updates.push('updated_at = NOW()');
        values.push(id);

        await pool.execute(
            `UPDATE announcements SET ${updates.join(', ')} WHERE id = ?`,
            values
        );

        res.json({
            success: true,
            message: '?????????'
        });

    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ??????
app.delete('/api/admin/announcements/:id', async (req, res) => {
    const { id } = req.params;

    try {
        await pool.execute('DELETE FROM announcements WHERE id = ?', [id]);

        res.json({
            success: true,
            message: '?????????'
        });

    } catch (error) {
        console.error('???????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ============================================
// ?????????API
// ============================================

// ?????????
app.get('/api/admin/profit-rules', async (req, res) => {
    try {
        const [rows] = await pool.execute(
            `SELECT * FROM profit_rules 
             WHERE is_active = 1
             ORDER BY created_at DESC`
        );

        res.json({
            success: true,
            data: rows.length > 0 ? rows[0] : {
                commission_rate: 10.00,
                rule_type: 'commission_rate',
                description: '?????????10%'
            }
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ?????????
app.put('/api/admin/profit-rules/:id', async (req, res) => {
    const { id } = req.params;
    const { commission_rate, rule_type, description, is_active } = req.body;

    try {
        const updates = [];
        const values = [];

        if (commission_rate !== undefined) {
            updates.push('commission_rate = ?');
            values.push(commission_rate);
        }
        if (rule_type !== undefined) {
            updates.push('rule_type = ?');
            values.push(rule_type);
        }
        if (description !== undefined) {
            updates.push('description = ?');
            values.push(description);
        }
        if (is_active !== undefined) {
            updates.push('is_active = ?');
            values.push(is_active ? 1 : 0);
        }
        updates.push('updated_at = NOW()');
        values.push(id);

        await pool.execute(
            `UPDATE profit_rules SET ${updates.join(', ')} WHERE id = ?`,
            values
        );

        res.json({
            success: true,
            message: '????????????'
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ?????????
app.post('/api/admin/profit-rules', async (req, res) => {
    const { rule_name, commission_rate = 10.00, rule_type = 'commission_rate', description } = req.body;

    try {
        // ???????????        await pool.execute('UPDATE profit_rules SET is_active = 0');

        const [result] = await pool.execute(
            `INSERT INTO profit_rules (rule_name, commission_rate, rule_type, description, is_active)
             VALUES (?, ?, ?, ?, 1)`,
            [rule_name || '?????????', commission_rate, rule_type, description || '?????????']
        );

        res.json({
            success: true,
            message: '????????????',
            data: { id: result.insertId }
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

app.get('/api/debug/passwords', async (req, res) => {
    console.log('?? ????????????????);

    try {
        const users = await passwordHelper.getAllUsersPasswordStatus();

        res.json({
            success: true,
            data: {
                total: users.length,
                users: users,
                summary: {
                    withPassword: users.filter(u => u.hasPassword).length,
                    withoutPassword: users.filter(u => !u.hasPassword).length
                }
            }
        });
    } catch (error) {
        console.error('????????:', error);
        res.status(500).json({
            success: false,
            message: '??????: ' + error.message
        });
    }
});

// 404???
app.use((req, res) => {
    console.log(`??404: ${req.method} ${req.url}`);
    res.status(404).json({
        success: false,
        message: '????????,
        path: req.url
    });
});

// ============================================
// ??????????????API
// ============================================

// ?????????????????
app.get('/api/admin/dashboard/stats', async (req, res) => {
    try {
        // ????????        const [todayOrders] = await pool.execute(
            `SELECT COUNT(*) AS total
             FROM orders
             WHERE DATE(created_at) = CURDATE()`
        );

        // ?????????????????????
        const [yesterdayOrders] = await pool.execute(
            `SELECT COUNT(*) AS total
             FROM orders
             WHERE DATE(created_at) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)`
        );

        // ??????????????????
        const [todayRevenue] = await pool.execute(
            `SELECT COALESCE(SUM(p.amount), 0) AS total
             FROM payments p
             WHERE DATE(p.created_at) = CURDATE()
             AND p.payment_status = 1`
        );

        // ????????????????????        const [yesterdayRevenue] = await pool.execute(
            `SELECT COALESCE(SUM(p.amount), 0) AS total
             FROM payments p
             WHERE DATE(p.created_at) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
             AND p.payment_status = 1`
        );

        // ???????????????????????        const [activeCouriers] = await pool.execute(
            `SELECT COUNT(DISTINCT cu.id) AS total
             FROM courier_users cu
             INNER JOIN orders o ON o.courier_user_id = cu.id
             WHERE DATE(o.created_at) = CURDATE()`
        );

        // ???????????????????????        const [yesterdayActiveCouriers] = await pool.execute(
            `SELECT COUNT(DISTINCT cu.id) AS total
             FROM courier_users cu
             INNER JOIN orders o ON o.courier_user_id = cu.id
             WHERE DATE(o.created_at) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)`
        );

        // ?????????????????? / ????????        const [completionRate] = await pool.execute(
            `SELECT 
                COUNT(*) AS total_orders,
                SUM(CASE WHEN status IN (3, 4, 7) THEN 1 ELSE 0 END) AS completed_orders
             FROM orders
             WHERE DATE(created_at) = CURDATE()`
        );

        // ???????????        const [yesterdayCompletionRate] = await pool.execute(
            `SELECT 
                COUNT(*) AS total_orders,
                SUM(CASE WHEN status IN (3, 4, 7) THEN 1 ELSE 0 END) AS completed_orders
             FROM orders
             WHERE DATE(created_at) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)`
        );

        // ????????        const todayOrdersCount = todayOrders[0]?.total || 0;
        const yesterdayOrdersCount = yesterdayOrders[0]?.total || 0;
        const todayOrdersGrowth = yesterdayOrdersCount > 0
            ? (((todayOrdersCount - yesterdayOrdersCount) / yesterdayOrdersCount) * 100).toFixed(1)
            : (todayOrdersCount > 0 ? 100 : 0);

        const todayRevenueTotal = todayRevenue[0]?.total || 0;
        const yesterdayRevenueTotal = yesterdayRevenue[0]?.total || 0;
        const todayRevenueGrowth = yesterdayRevenueTotal > 0
            ? (((todayRevenueTotal - yesterdayRevenueTotal) / yesterdayRevenueTotal) * 100).toFixed(1)
            : (todayRevenueTotal > 0 ? 100 : 0);

        const activeCouriersCount = activeCouriers[0]?.total || 0;
        const yesterdayActiveCouriersCount = yesterdayActiveCouriers[0]?.total || 0;
        const activeCouriersGrowth = yesterdayActiveCouriersCount > 0
            ? (((activeCouriersCount - yesterdayActiveCouriersCount) / yesterdayActiveCouriersCount) * 100).toFixed(1)
            : (activeCouriersCount > 0 ? 100 : 0);

        const totalOrdersToday = completionRate[0]?.total_orders || 0;
        const completedOrdersToday = completionRate[0]?.completed_orders || 0;
        const completionRateToday = totalOrdersToday > 0
            ? ((completedOrdersToday / totalOrdersToday) * 100).toFixed(1)
            : 0;

        const totalOrdersYesterday = yesterdayCompletionRate[0]?.total_orders || 0;
        const completedOrdersYesterday = yesterdayCompletionRate[0]?.completed_orders || 0;
        const completionRateYesterday = totalOrdersYesterday > 0
            ? ((completedOrdersYesterday / totalOrdersYesterday) * 100).toFixed(1)
            : 0;
        const completionRateGrowth = completionRateYesterday > 0
            ? (parseFloat(completionRateToday) - parseFloat(completionRateYesterday)).toFixed(1)
            : (completionRateToday > 0 ? parseFloat(completionRateToday) : 0);

        res.json({
            success: true,
            data: {
                todayOrders: todayOrdersCount,
                todayOrdersGrowth: parseFloat(todayOrdersGrowth),
                todayRevenue: todayRevenueTotal,
                todayRevenueGrowth: parseFloat(todayRevenueGrowth),
                activeCouriers: activeCouriersCount,
                activeCouriersGrowth: parseFloat(activeCouriersGrowth),
                completionRate: parseFloat(completionRateToday),
                completionRateGrowth: parseFloat(completionRateGrowth)
            }
        });

    } catch (error) {
        console.error('?????????????????:', error);
        res.status(500).json({ success: false, message: '?????????' });
    }
});

// ?????????????????????
app.get('/api/admin/dashboard/order-trend', async (req, res) => {
    const { period = 'week' } = req.query || {};

    try {
        let dateCondition = '';
        let groupBy = 'DATE(o.created_at)';

        if (period === 'week') {
            dateCondition = 'o.created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)';
            groupBy = 'DATE(o.created_at)';
        } else if (period === 'month') {
            dateCondition = 'o.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)';
            groupBy = 'DATE(o.created_at)';
        } else if (period === 'year') {
            dateCondition = 'o.created_at >= DATE_SUB(NOW(), INTERVAL 365 DAY)';
            groupBy = 'YEAR(o.created_at), MONTH(o.created_at)';
        }

        const [rows] = await pool.execute(
            `SELECT 
                ${groupBy === 'DATE(o.created_at)' ? 'DATE(o.created_at) AS date' : 'CONCAT(YEAR(o.created_at), "-", LPAD(MONTH(o.created_at), 2, "0")) AS date'},
                COUNT(*) AS count
             FROM orders o
             WHERE ${dateCondition}
             GROUP BY ${groupBy}
             ORDER BY date ASC`
        );

        res.json({
            success: true,
            data: rows
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ?????????????????????
app.get('/api/admin/dashboard/income-distribution', async (req, res) => {
    const { period = 'month' } = req.query || {};

    try {
        let dateCondition = '';

        if (period === 'month') {
            dateCondition = 'MONTH(p.created_at) = MONTH(NOW()) AND YEAR(p.created_at) = YEAR(NOW())';
        } else if (period === 'quarter') {
            dateCondition = 'QUARTER(p.created_at) = QUARTER(NOW()) AND YEAR(p.created_at) = YEAR(NOW())';
        } else if (period === 'year') {
            dateCondition = 'YEAR(p.created_at) = YEAR(NOW())';
        }

        // payments ?????payment_method ???????????        const [rows] = await pool.execute(
            `SELECT 
                SUM(p.amount) AS total
             FROM payments p
             WHERE ${dateCondition} AND p.payment_status = 1`
        );

        // ???????????????????????????????        const totalAmount = parseFloat(rows[0]?.total || 0);

        res.json({
            success: true,
            data: {
                wechat: 0,
                alipay: 0,
                balance: 0,
                other: totalAmount
            }
        });

    } catch (error) {
        console.error('??????????????:', error);
        res.status(500).json({ success: false, message: '??????' });
    }
});

// ============================================
// ?????????API
// ============================================

// ??? ??????logs ?????? adminRoutes.js ?????
// ??? ??????/api/orders/available ?????? orderRoutes.js ?????// ?????app.js ????????????????????
// ============================================
// ?????????API
// ============================================

// ??? ??????permissions ?????? adminRoutes.js ?????
// ============================================
// ?????????API
// ============================================

// ??? ??????settings ?????? adminRoutes.js ?????
// ??????
app.use((err, req, res, next) => {
    console.error('?? ????????', err);
    res.status(500).json({
        success: false,
        message: '???????????,
        error: process.env.NODE_ENV === 'development' ? err.message : undefined
    });
});

// ????????app.listen(port, () => {
    console.log(`?? ????????? http://localhost:${port}`);
    console.log(`?? ??????? http://localhost:${port}/api/health`);
    console.log(`?? ??????: http://localhost:${port}/api/hello`);
    console.log(`?? ??????: http://localhost:${port}/api/debug/users`);
});

console.log('??app.js ??????');
a p p . u s e ( " / u p l o a d s " ,   e x p r e s s . s t a t i c ( u p l o a d D i r ) ) ; 
 
 a p p . u s e ( e r r o r H a n d l e r ) ; 
 
 